mcp: validation only for accept action (#766)

Fix: #758

- validate schema only for accept action
- add unit test
This commit is contained in:
FanOne 2026-01-29 00:06:06 +08:00 • committed by GitHub
commit b29ab52878
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 73 additions and 1 deletions

View file

@ -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)}

View file

@ -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)
}
})
}
}

View file

@ -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
}