From b29ab52878a105fc59a540487437490a82d9ef8a Mon Sep 17 00:00:00 2001 From: FanOne <294350394@qq.com> Date: Thu, 29 Jan 2026 00:06:06 +0800 Subject: [PATCH] mcp: validation only for accept action (#766) Fix: #758 - validate schema only for accept action - add unit test --- mcp/client.go | 2 +- mcp/elicitation_test.go | 68 +++++++++++++++++++++++++++++++++++++++++ mcp/server.go | 4 +++ 3 files changed, 73 insertions(+), 1 deletion(-) diff --git a/mcp/client.go b/mcp/client.go index 57c30fb..a167047 100644 --- a/mcp/client.go +++ b/mcp/client.go @@ -590,7 +590,7 @@ func (c *Client) elicit(ctx context.Context, req *ElicitRequest) (*ElicitResult, return nil, err } // Validate elicitation result content against requested schema. - if schema != nil && res.Content != nil { + if res.Action == "accept" && schema != nil && res.Content != nil { resolved, err := schema.Resolve(nil) if err != nil { return nil, &jsonrpc.Error{Code: jsonrpc.CodeInvalidParams, Message: fmt.Sprintf("failed to resolve requested schema: %v", err)} diff --git a/mcp/elicitation_test.go b/mcp/elicitation_test.go index 52ae1d7..bfa71e7 100644 --- a/mcp/elicitation_test.go +++ b/mcp/elicitation_test.go @@ -201,3 +201,71 @@ func TestElicitationCompleteNotification(t *testing.T) { t.Fatal("timed out waiting for elicitation complete notification") } } + +func TestElicitationNoValidationWithoutAccept(t *testing.T) { + ctx := context.Background() + + schema := &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "test": {Type: "string"}, + }, + Required: []string{"test"}, + } + + testCases := []struct { + name string + action string + content map[string]any + wantAction string + }{ + { + name: "cancel action", + action: "cancel", + content: nil, // Empty content should be ignored + wantAction: "cancel", + }, + { + name: "decline action", + action: "decline", + content: map[string]any{}, // Empty content should be ignored + wantAction: "decline", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + ct, st := NewInMemoryTransports() + s := NewServer(testImpl, nil) + ss, err := s.Connect(ctx, st, nil) + if err != nil { + t.Fatal(err) + } + defer ss.Close() + + c := NewClient(testImpl, &ClientOptions{ + ElicitationHandler: func(context.Context, *ElicitRequest) (*ElicitResult, error) { + return &ElicitResult{Action: tc.action, Content: tc.content}, nil + }, + }) + cs, err := c.Connect(ctx, ct, nil) + if err != nil { + t.Fatal(err) + } + defer cs.Close() + + res, err := ss.Elicit(ctx, &ElicitParams{ + Message: "Test bug", + RequestedSchema: schema, + }) + + if err != nil { + t.Fatalf("Elicit failed: %v", err) + } + + if res.Action != tc.wantAction { + t.Errorf("Expected action %q, got %q", tc.wantAction, res.Action) + } + }) + } +} diff --git a/mcp/server.go b/mcp/server.go index 687e799..d68a8c2 100644 --- a/mcp/server.go +++ b/mcp/server.go @@ -1218,6 +1218,10 @@ func (ss *ServerSession) Elicit(ctx context.Context, params *ElicitParams) (*Eli return nil, err } + if res.Action != "accept" { + return res, nil + } + if params.RequestedSchema == nil { return res, nil }