mcp: allow restricting the protocol versions a server supports (#1199)
Fixes #945
This commit is contained in:
parent
5a89b63764
commit
21c18c6229
1 changed files with 397 additions and 35 deletions
|
|
@ -4141,3 +4141,80 @@ func TestStreamableMaxRequestBodyBytes(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestStreamableSupportedProtocolVersions_Header verifies that the
|
||||
// MCP-Protocol-Version header is validated against
|
||||
// [ServerOptions.SupportedProtocolVersions], and not merely against the
|
||||
// versions the SDK knows about.
|
||||
func TestStreamableSupportedProtocolVersions_Header(t *testing.T) {
|
||||
const initBody = `{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}`
|
||||
|
||||
newServer := func(t *testing.T, stateless bool) *httptest.Server {
|
||||
server := NewServer(testImpl, &ServerOptions{
|
||||
SupportedProtocolVersions: []string{protocolVersion20251125},
|
||||
})
|
||||
handler := NewStreamableHTTPHandler(func(*http.Request) *Server { return server },
|
||||
&StreamableHTTPOptions{Stateless: stateless})
|
||||
httpServer := httptest.NewServer(handler)
|
||||
t.Cleanup(httpServer.Close)
|
||||
return httpServer
|
||||
}
|
||||
post := func(t *testing.T, url, version, sessionID string) *http.Response {
|
||||
t.Helper()
|
||||
req, err := http.NewRequest(http.MethodPost, url, strings.NewReader(initBody))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Accept", "application/json, text/event-stream")
|
||||
req.Header.Set(protocolVersionHeader, version)
|
||||
if sessionID != "" {
|
||||
req.Header.Set(sessionIDHeader, sessionID)
|
||||
}
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return resp
|
||||
}
|
||||
|
||||
for _, stateless := range []bool{false, true} {
|
||||
for _, test := range []struct {
|
||||
version string
|
||||
wantStatus int
|
||||
}{
|
||||
{protocolVersion20251125, http.StatusOK},
|
||||
// Supported by the SDK, but excluded by the server.
|
||||
{protocolVersion20250618, http.StatusBadRequest},
|
||||
// Unknown to the SDK: rejected before any server is consulted.
|
||||
{"1999-01-01", http.StatusBadRequest},
|
||||
} {
|
||||
t.Run(fmt.Sprintf("stateless=%v/%s", stateless, test.version), func(t *testing.T) {
|
||||
resp := post(t, newServer(t, stateless).URL, test.version, "")
|
||||
defer resp.Body.Close()
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
if resp.StatusCode != test.wantStatus {
|
||||
t.Errorf("status = %d, want %d; body = %s", resp.StatusCode, test.wantStatus, body)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("existing session", func(t *testing.T) {
|
||||
httpServer := newServer(t, false)
|
||||
resp := post(t, httpServer.URL, protocolVersion20251125, "")
|
||||
io.Copy(io.Discard, resp.Body)
|
||||
resp.Body.Close()
|
||||
sessionID := resp.Header.Get(sessionIDHeader)
|
||||
if sessionID == "" {
|
||||
t.Fatalf("initialize response missing %s header", sessionIDHeader)
|
||||
}
|
||||
|
||||
resp = post(t, httpServer.URL, protocolVersion20250618, sessionID)
|
||||
defer resp.Body.Close()
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
if resp.StatusCode != http.StatusBadRequest {
|
||||
t.Errorf("status = %d, want %d; body = %s", resp.StatusCode, http.StatusBadRequest, body)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue