mcp: validation only for accept action (#766)
Fix: #758 - validate schema only for accept action - add unit test
This commit is contained in:
parent
fe6d3cf74a
commit
b29ab52878
3 changed files with 73 additions and 1 deletions
|
|
@ -590,7 +590,7 @@ func (c *Client) elicit(ctx context.Context, req *ElicitRequest) (*ElicitResult,
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Validate elicitation result content against requested schema.
|
// 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)
|
resolved, err := schema.Resolve(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, &jsonrpc.Error{Code: jsonrpc.CodeInvalidParams, Message: fmt.Sprintf("failed to resolve requested schema: %v", err)}
|
return nil, &jsonrpc.Error{Code: jsonrpc.CodeInvalidParams, Message: fmt.Sprintf("failed to resolve requested schema: %v", err)}
|
||||||
|
|
|
||||||
|
|
@ -201,3 +201,71 @@ func TestElicitationCompleteNotification(t *testing.T) {
|
||||||
t.Fatal("timed out waiting for elicitation complete notification")
|
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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1218,6 +1218,10 @@ func (ss *ServerSession) Elicit(ctx context.Context, params *ElicitParams) (*Eli
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if res.Action != "accept" {
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
if params.RequestedSchema == nil {
|
if params.RequestedSchema == nil {
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue