tools/call with "arguments": null panics the server when the tool schema has a default
维护者通常 1 天内回复
还没有人认领这个 Issue。
评估
调研方向
从 mcp/tool.go 中的 applySchema 开始,将其对 null 的处理与 issue 中提到的输出分支进行比较。为带有 null 参数和 schema 默认值的 tools/call 请求添加回归测试;完成标准是该请求不再引发 panic,并且要么应用默认值,要么返回 JSON-RPC 错误或工具错误。
由索引模型根据 Issue 内容生成。
描述
Describe the bug
A tools/call request with "arguments": null panics the whole server process when the tool's input schema declares a default.
applySchema in mcp/tool.go unmarshals the arguments into v := make(map[string]any). Unmarshalling JSON null sets v to a nil map, which still passes the unmarshaled.(map[string]any) check, so resolved.ApplyDefaults runs and jsonschema-go writes the default into the nil map:
panic: assignment to entry in nil map
The panic happens in the goroutine handling the request and nothing recovers it, so a single request takes the process down for every client. Omitting arguments or sending {} works and applies the default.
This is the same root cause as #1062, fixed for elicitation in #1068 ("jsonschema-go can panic when applying defaults into a nil map"). The tool-call path through applySchema is not covered by that fix.
To Reproduce
Versions: go-sdk v1.8.0 and main at 25a53e3, github.com/google/jsonschema-go v0.4.3, Go 1.27.1.
package main
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"net/http/httptest"
"strings"
"github.com/google/jsonschema-go/jsonschema"
"github.com/modelcontextprotocol/go-sdk/mcp"
)
type input struct {
Limit int `json:"limit,omitempty"`
}
func main() {
schema, err := jsonschema.For[input](nil)
if err != nil {
panic(err)
}
schema.Properties["limit"].Default = json.RawMessage("20")
server := mcp.NewServer(&mcp.Implementation{Name: "repro", Version: "v0.0.1"}, nil)
mcp.AddTool(server, &mcp.Tool{Name: "list", InputSchema: schema},
func(_ context.Context, _ *mcp.CallToolRequest, in input) (*mcp.CallToolResult, any, error) {
return nil, map[string]int{"limit": in.Limit}, nil
})
handler := mcp.NewStreamableHTTPHandler(func(*http.Request) *mcp.Server { return server },
&mcp.StreamableHTTPOptions{Stateless: true, JSONResponse: true})
ts := httptest.NewServer(handler)
defer ts.Close()
body := `{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"list","arguments":null}}`
req, _ := http.NewRequest(http.MethodPost, ts.URL, strings.NewReader(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json, text/event-stream")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
out, _ := io.ReadAll(resp.Body)
fmt.Println(resp.StatusCode, string(out))
}
-
go run . -
The process exits with the panic shown under Logs.
-
Replace
"arguments":nullwith"arguments":{}, or drop the field: the program prints200 {"jsonrpc":"2.0","id":1,"result":{"content":[{"type":"text","text":"{\"limit\":20}"}],"structuredContent":{"limit":20}}}
Expected behavior
"arguments": null is treated like omitted or empty arguments: defaults are applied and the call proceeds. Rejecting it with a JSON-RPC or tool error would also be acceptable. Either way, the process should not crash.
Logs
panic: assignment to entry in nil map
goroutine 37 [running]:
reflect.mapassign_faststr0(...)
reflect.Value.SetMapIndex(...)
github.com/google/jsonschema-go/jsonschema.(*state).applyDefaults(...)
github.com/google/[email protected]/jsonschema/validate.go:741
github.com/google/jsonschema-go/jsonschema.(*Resolved).ApplyDefaults(...)
github.com/google/[email protected]/jsonschema/validate.go:701
github.com/modelcontextprotocol/go-sdk/mcp.applySchema(...)
github.com/modelcontextprotocol/[email protected]/mcp/tool.go:117
github.com/modelcontextprotocol/go-sdk/mcp.toolForErr[...].func1(...)
github.com/modelcontextprotocol/[email protected]/mcp/server.go:402
github.com/modelcontextprotocol/go-sdk/mcp.(*Server).callTool(...)
github.com/modelcontextprotocol/[email protected]/mcp/server.go:1013
Additional context
Possible fixes:
-
In
applySchema, fall back to an empty map when the unmarshalled input is nil, mirroring what the output branch already does fornull:if v == nil { v = map[string]any{} } -
Or make
ApplyDefaultsin jsonschema-go tolerate a nil map, which would also cover the elicitation paths patched in #1068.
Workaround until a fix lands: a receiving middleware that drops null arguments before the tool handler runs.
server.AddReceivingMiddleware(func(next mcp.MethodHandler) mcp.MethodHandler {
return func(ctx context.Context, method string, req mcp.Request) (mcp.Result, error) {
if params, ok := req.GetParams().(*mcp.CallToolParamsRaw); ok &&
bytes.Equal(bytes.TrimSpace(params.Arguments), []byte("null")) {
params.Arguments = nil
}
return next(ctx, method, req)
}
})
- 主要语言
- Go
- 星标
- 5.3k
- 派生
- 607
- 平均合并
- 1 天 7 小时
- 30 天内合并 PR
- 81
环境准备
在浏览器里用你自己的 GitHub 账号启动这个项目的开发容器。
- 没有 Dockerfile 或 Docker Compose 文件
- 有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
modelcontextprotocol/go-sdk 的其他 Issue
-
难度 2/5 1-3 小时 新手友好度 78/100
modelcontextprotocol/go-sdk#1512 ·
维护者通常 1 天内回复
-
Expose generic `SendNotification` on `ServerSession` for custom protocol extensions可能重新可做 关联的 PR 已关闭且未合并。 未关闭needs investigation
难度 2/5 1-3 小时 新手友好度 72/100
modelcontextprotocol/go-sdk#745 · 13 条评论 · 1 个 reaction ·
维护者通常 1 天内回复
-
难度 3/5 1-2 天 新手友好度 62/100
modelcontextprotocol/go-sdk#1506 · 2 条评论 ·
维护者通常 1 天内回复
-
mcp: closing a session right after a cancelled call drops notifications/cancelled, so the server handler keeps running可能已有人在做 @vshalpnjabi 于 1 天前认领。 未关闭
难度 4/5 3-5 天 新手友好度 48/100
modelcontextprotocol/go-sdk#1505 · 1 条评论 ·
维护者通常 1 天内回复
-
mcp: list_changed can only be broadcast; a server cannot notify one session (2026-07-28 subscriptions/listen)可能已有人在做 @nahapetyan-serob 于 1 天前认领。 未关闭
难度 4/5 1-2 天 新手友好度 32/100
modelcontextprotocol/go-sdk#1480 · 1 条评论 · 已指派 2 人 ·
维护者通常 1 天内回复
查看 modelcontextprotocol/go-sdk 的全部 Issue
相似的 Issue
-
area: metrics area: tracing contribfest enhancement good first issue
难度 2/5 1-3 小时 新手友好度 83/100
open-telemetry/opentelemetry-ebpf-instrumentation#4188 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 74/100
blinklabs-io/dingo#6074 ·
维护者通常 1 天内回复
-
kind/bug remote
难度 2/5 1-3 小时 新手友好度 68/100
podman-container-tools/podman#30143 ·
维护者通常 1 天内回复
-
component/mesheryctl kind/bug language/go
难度 1/5 1 小时以内 新手友好度 88/100
meshery/meshery#22993 · 2 条评论 ·
维护者通常 1 天内回复
-
enhancement
难度 2/5 1-3 小时 新手友好度 64/100