mcp: custom methods rejected on a StreamableServerTransport connected with Server.Connect
维护者通常 1 天内回复
还没有人认领这个 Issue。
评估
- 难度
- 3/5
- 预计耗时
- 1-2 天
- 新手友好度
- 62/100
- Issue 类型
- 缺陷
- 描述清晰度
- 描述清楚
- 活跃度
- 活跃
- 技术栈
- go
调研方向
Start with the POST pre-check in mcp/streamable.go:1695 and compare how connectStreamable sets c.server and toolLookup with the path used by Server.Connect. The report says custom methods fail on directly connected StreamableServerTransport sessions while standard methods succeed; trace that setup and add a regression test based on the supplied reproduction. Done means the custom method reaches its handler and the request returns HTTP 200.
由索引模型根据 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 method registered with AddReceivingCustomMethod fails with HTTP 400 (JSON RPC not handled: "acme/search" unsupported) on a StreamableServerTransport connected with Server.Connect and served through its ServeHTTP. Standard methods on the same session succeed, and the custom method works through StreamableHTTPHandler.
The POST pre-check falls back to the standard-only serverMethodInfos when c.server is nil (mcp/streamable.go:1695). c.server is set only in connectStreamable (streamable.go:603), which Server.Connect does not call. This is the Streamable HTTP counterpart of #1291 (fixed for SSE in #1292).
Expected: the custom method reaches its handler. A possible fix is for Server.Connect to set the connection's server (and toolLookup, which has the same gap) as connectStreamable does.
We hit this serving the Skills extension (SEP-2640): skills/list, skills/get and resources/directory/read are custom methods, so they fail this way on a resumed session.
How to reproduce
package repro
import (
"context"
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/modelcontextprotocol/go-sdk/mcp"
)
type searchParams struct {
mcp.ParamsBase
Query string `json:"query"`
}
type searchResult struct {
mcp.ResultBase
Hits []string `json:"hits"`
}
func TestCustomMethodOnDirectlyConnectedSession(t *testing.T) {
s := mcp.NewServer(&mcp.Implementation{Name: "s", Version: "1"}, nil)
if err := mcp.AddReceivingCustomMethod(s, "acme/search",
func(context.Context, *mcp.ServerSession, *searchParams) (*searchResult, error) {
return &searchResult{Hits: []string{"hit"}}, nil
}); err != nil {
t.Fatal(err)
}
// Connect a session directly, e.g. to resume one from a shared store.
tr := &mcp.StreamableServerTransport{SessionID: "s1"}
state := &mcp.ServerSessionState{
InitializeParams: &mcp.InitializeParams{ProtocolVersion: "2025-11-25"},
InitializedParams: &mcp.InitializedParams{},
}
ss, err := s.Connect(context.Background(), tr, &mcp.ServerSessionOptions{State: state})
if err != nil {
t.Fatal(err)
}
defer ss.Close()
ts := httptest.NewServer(tr)
defer ts.Close()
req, _ := http.NewRequest(http.MethodPost, ts.URL,
strings.NewReader(`{"jsonrpc":"2.0","id":1,"method":"acme/search","params":{"query":"x"}}`))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json, text/event-stream")
req.Header.Set("Mcp-Session-Id", "s1")
req.Header.Set("Mcp-Protocol-Version", "2025-11-25")
resp, err := http.DefaultClient.Do(req)
if err != nil {
t.Fatal(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
if resp.StatusCode != http.StatusOK {
t.Fatalf("got HTTP %d: %s", resp.StatusCode, body)
}
}
Output: `got HTTP 400: JSON RPC not handled: "acme/search" unsupported`. The same request with method `tools/list` returns 200, and calling `acme/search` through `NewStreamableHTTPHandler` with `CallCustomMethod` succeeds.
Paste everything between the outer four-backtick fence, including the inner fence, so GitHub renders it as code.
Where did you hit this?
ToolHive's multi-replica Virtual MCP Server, which serves MCP through go-sdk and resumes a session on another replica by connecting a StreamableServerTransport with Server.Connect.
Go MCP SDK version
v1.8.0; also reproduced on main at caa354d.
Go version
go version go1.27.1 darwin/arm64
Logs
acme/search: 400 JSON RPC not handled: "acme/search" unsupported
- 主要语言
- 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 天内回复
-
mcp: closing a session right after a cancelled call drops notifications/cancelled, so the server handler keeps running可能已有人在做 @vshalpnjabi 于 2 天前认领。 未关闭
难度 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 天内回复
-
mcp: Client.Connect falls back to initialize after a 401 on server/discover, running the authorization flow twice可能已有人在做 @kerthans 于 18 天前认领。 未关闭
难度 3/5 1-2 天 新手友好度 35/100
modelcontextprotocol/go-sdk#1423 · 1 条评论 ·
维护者通常 1 天内回复
查看 modelcontextprotocol/go-sdk 的全部 Issue
相似的 Issue
-
bug
难度 2/5 1-3 小时 新手友好度 80/100
-
/shutdown/ready can fail to return an HTTP response when readiness takes longer than the server write timeout可能已有人在做 @floriankoch 今天认领。 未关闭triage
难度 2/5 1-3 小时 新手友好度 76/100
envoyproxy/gateway#10562 ·
维护者通常 1 天内回复
-
Adding an LDAP group reports every search failure as "LDAP Group DN is not found"可能已有人在做 @Daksha1611 今天认领。 未关闭
难度 2/5 1-3 小时 新手友好度 76/100
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 70/100
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 75/100