mcp: custom methods rejected on a StreamableServerTransport connected with Server.Connect
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Idoneità per principianti
- 62/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Stack tecnologico
- go
- Ambito
- backend-api-design
Direzione di ricerca
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.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
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
- Lingua principale
- Go
- Stelle
- 5.3k
- Fork
- 607
- Merge medio
- 1g 11h
- PR unite (30g)
- 82
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
-
Expose generic `SendNotification` on `ServerSession` for custom protocol extensionsForse di nuovo libera Una pull request per questa issue è stata chiusa senza essere unita. 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
-
mcp: whether MaxLineLength rejects a message depends on how the stream is readForse già presa @Tangerg l’ha presa oggi. Aperta
modelcontextprotocol/go-sdk#1509 · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
-
mcp: closing a session right after a cancelled call drops notifications/cancelled, so the server handler keeps runningForse già presa @vshalpnjabi l’ha presa oggi. Aperta
Difficoltà 4/5 3-5 giorni Idoneità per principianti 48/100
modelcontextprotocol/go-sdk#1505 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
mcp: a canceled write on IOTransport/StdioTransport cannot leave the write queueForse già presa @Tangerg l’ha presa 1 giorno fa. Aperta
modelcontextprotocol/go-sdk#1498 · 1 commento · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
-
mcp: list_changed can only be broadcast; a server cannot notify one session (2026-07-28 subscriptions/listen)Forse già presa @huynle-dev l’ha presa 4 giorni fa. Aperta
Difficoltà 4/5 1-2 giorni Idoneità per principianti 32/100
modelcontextprotocol/go-sdk#1480 · 1 commento · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di modelcontextprotocol/go-sdk
Issue simili
-
enhancement needs:sonnet ready-for-agent
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 84/100
microsoft/TypeScript#65370 ·
I maintainer di solito rispondono entro 1 giorno
-
docs: data-ownership invites vendors to build add-ons around the OSForse già presa @brandli l’ha presa oggi. Aperta
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 85/100
gentian-org/gentian-os#894 ·
I maintainer di solito rispondono entro 1 giorno
-
bug tech debt testing
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
aws/amazon-vpc-cni-k8s#3976 ·
I maintainer di solito rispondono entro 1 giorno
-
bug raised-by:desk
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
medici-finance/assay#5678 ·
I maintainer di solito rispondono entro 1 giorno