mcp: add ServerSession.NotifyElicitationComplete (#1194)
Adds: ```go func (ss *ServerSession) NotifyElicitationComplete(ctx context.Context, params *ElicitationCompleteParams) error ``` As according to [spec](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/schema/2025-11-25/schema.ts#L2493-L2501)
This commit is contained in:
parent
3d6450fccf
commit
6f0a645c20
3 changed files with 53 additions and 6 deletions
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"testing/synctest"
|
"testing/synctest"
|
||||||
|
|
||||||
"github.com/google/jsonschema-go/jsonschema"
|
"github.com/google/jsonschema-go/jsonschema"
|
||||||
|
"github.com/modelcontextprotocol/go-sdk/internal/jsonrpc2"
|
||||||
"github.com/modelcontextprotocol/go-sdk/jsonrpc"
|
"github.com/modelcontextprotocol/go-sdk/jsonrpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -194,9 +195,9 @@ func TestElicitationCompleteNotification(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Server sends elicitation complete notification (simulating out-of-band completion)
|
// 2. Server sends elicitation complete notification (simulating out-of-band completion)
|
||||||
err = handleNotify(ctx, notificationElicitationComplete, newServerRequest(ss, &ElicitationCompleteParams{
|
err = ss.NotifyElicitationComplete(ctx, &ElicitationCompleteParams{
|
||||||
ElicitationID: elicitID,
|
ElicitationID: elicitID,
|
||||||
}))
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to send elicitation complete notification: %v", err)
|
t.Fatalf("failed to send elicitation complete notification: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -209,6 +210,41 @@ func TestElicitationCompleteNotification(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNotifyElicitationCompleteInvalidParams(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
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, nil)
|
||||||
|
cs, err := c.Connect(ctx, ct, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cs.Close()
|
||||||
|
|
||||||
|
// An empty elicitation ID cannot be matched to a pending elicitation by the
|
||||||
|
// client, so it is rejected rather than sent.
|
||||||
|
for _, tc := range []struct {
|
||||||
|
name string
|
||||||
|
params *ElicitationCompleteParams
|
||||||
|
}{
|
||||||
|
{"nil params", nil},
|
||||||
|
{"empty ID", &ElicitationCompleteParams{}},
|
||||||
|
} {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
err := ss.NotifyElicitationComplete(ctx, tc.params)
|
||||||
|
if !errors.Is(err, jsonrpc2.ErrInvalidParams) {
|
||||||
|
t.Errorf("NotifyElicitationComplete(%v) = %v, want %v", tc.params, err, jsonrpc2.ErrInvalidParams)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestElicitationNoValidationWithoutAccept(t *testing.T) {
|
func TestElicitationNoValidationWithoutAccept(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -300,10 +300,9 @@ func TestURLElicitationRequired(t *testing.T) {
|
||||||
// In a real scenario, this would happen out-of-band after the user
|
// In a real scenario, this would happen out-of-band after the user
|
||||||
// completes the form submission.
|
// completes the form submission.
|
||||||
go func() {
|
go func() {
|
||||||
err := handleNotify(ctx, notificationElicitationComplete,
|
err := ss.NotifyElicitationComplete(ctx, &ElicitationCompleteParams{
|
||||||
newServerRequest(ss, &ElicitationCompleteParams{
|
ElicitationID: elicitID,
|
||||||
ElicitationID: elicitID,
|
})
|
||||||
}))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("failed to send elicitation complete notification: %v", err)
|
t.Errorf("failed to send elicitation complete notification: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1733,6 +1733,18 @@ func (ss *ServerSession) Elicit(ctx context.Context, params *ElicitParams) (*Eli
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NotifyElicitationComplete tells the client that the out-of-band ("url" mode)
|
||||||
|
// elicitation identified by params.ElicitationID has finished.
|
||||||
|
func (ss *ServerSession) NotifyElicitationComplete(ctx context.Context, params *ElicitationCompleteParams) error {
|
||||||
|
if params == nil {
|
||||||
|
return fmt.Errorf("%w: params cannot be nil", jsonrpc2.ErrInvalidParams)
|
||||||
|
}
|
||||||
|
if params.ElicitationID == "" {
|
||||||
|
return fmt.Errorf("%w: ElicitationID cannot be empty", jsonrpc2.ErrInvalidParams)
|
||||||
|
}
|
||||||
|
return handleNotify(ctx, notificationElicitationComplete, newServerRequest(ss, orZero[Params](params)))
|
||||||
|
}
|
||||||
|
|
||||||
// Log sends a log message to the client.
|
// Log sends a log message to the client.
|
||||||
//
|
//
|
||||||
// For new-protocol (>= 2026-07-28) requests, the level is taken from the
|
// For new-protocol (>= 2026-07-28) requests, the level is taken from the
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue