@@ -3,7 +3,6 @@ package client
33import (
44 "context"
55 "encoding/json"
6- "errors"
76 "fmt"
87 "slices"
98 "sync"
@@ -25,6 +24,7 @@ type Client struct {
2524 serverCapabilities mcp.ServerCapabilities
2625 protocolVersion string
2726 samplingHandler SamplingHandler
27+ elicitationHandler ElicitationHandler
2828}
2929
3030type ClientOption func (* Client )
@@ -44,6 +44,14 @@ func WithSamplingHandler(handler SamplingHandler) ClientOption {
4444 }
4545}
4646
47+ // WithElicitationHandler sets the elicitation handler for the client.
48+ // When set, the client will declare elicitation capability during initialization.
49+ func WithElicitationHandler (handler ElicitationHandler ) ClientOption {
50+ return func (c * Client ) {
51+ c .elicitationHandler = handler
52+ }
53+ }
54+
4755// WithSession assumes a MCP Session has already been initialized
4856func WithSession () ClientOption {
4957 return func (c * Client ) {
@@ -77,9 +85,16 @@ func (c *Client) Start(ctx context.Context) error {
7785 if c .transport == nil {
7886 return fmt .Errorf ("transport is nil" )
7987 }
80- err := c .transport .Start (ctx )
81- if err != nil {
82- return err
88+
89+ if _ , ok := c .transport .(* transport.Stdio ); ! ok {
90+ // the stdio transport from NewStdioMCPClientWithOptions
91+ // is already started, dont start again.
92+ //
93+ // Start the transport for other transport types
94+ err := c .transport .Start (ctx )
95+ if err != nil {
96+ return err
97+ }
8398 }
8499
85100 c .transport .SetNotificationHandler (func (notification mcp.JSONRPCNotification ) {
@@ -150,7 +165,7 @@ func (c *Client) sendRequest(
150165 }
151166
152167 if response .Error != nil {
153- return nil , errors . New ( response .Error .Message )
168+ return nil , response .Error .AsError ( )
154169 }
155170
156171 return & response .Result , nil
@@ -167,6 +182,10 @@ func (c *Client) Initialize(
167182 if c .samplingHandler != nil {
168183 capabilities .Sampling = & struct {}{}
169184 }
185+ // Add elicitation capability if handler is configured
186+ if c .elicitationHandler != nil {
187+ capabilities .Elicitation = & struct {}{}
188+ }
170189
171190 // Ensure we send a params object with all required fields
172191 params := struct {
@@ -451,11 +470,15 @@ func (c *Client) Complete(
451470}
452471
453472// handleIncomingRequest processes incoming requests from the server.
454- // This is the main entry point for server-to-client requests like sampling.
473+ // This is the main entry point for server-to-client requests like sampling and elicitation .
455474func (c * Client ) handleIncomingRequest (ctx context.Context , request transport.JSONRPCRequest ) (* transport.JSONRPCResponse , error ) {
456475 switch request .Method {
457476 case string (mcp .MethodSamplingCreateMessage ):
458477 return c .handleSamplingRequestTransport (ctx , request )
478+ case string (mcp .MethodElicitationCreate ):
479+ return c .handleElicitationRequestTransport (ctx , request )
480+ case string (mcp .MethodPing ):
481+ return c .handlePingRequestTransport (ctx , request )
459482 default :
460483 return nil , fmt .Errorf ("unsupported request method: %s" , request .Method )
461484 }
@@ -516,14 +539,60 @@ func (c *Client) handleSamplingRequestTransport(ctx context.Context, request tra
516539 }
517540
518541 // Create the transport response
519- response := & transport.JSONRPCResponse {
520- JSONRPC : mcp .JSONRPC_VERSION ,
521- ID : request .ID ,
522- Result : json .RawMessage (resultBytes ),
542+ response := transport .NewJSONRPCResultResponse (request .ID , json .RawMessage (resultBytes ))
543+
544+ return response , nil
545+ }
546+
547+ // handleElicitationRequestTransport handles elicitation requests at the transport level.
548+ func (c * Client ) handleElicitationRequestTransport (ctx context.Context , request transport.JSONRPCRequest ) (* transport.JSONRPCResponse , error ) {
549+ if c .elicitationHandler == nil {
550+ return nil , fmt .Errorf ("no elicitation handler configured" )
523551 }
524552
553+ // Parse the request parameters
554+ var params mcp.ElicitationParams
555+ if request .Params != nil {
556+ paramsBytes , err := json .Marshal (request .Params )
557+ if err != nil {
558+ return nil , fmt .Errorf ("failed to marshal params: %w" , err )
559+ }
560+ if err := json .Unmarshal (paramsBytes , & params ); err != nil {
561+ return nil , fmt .Errorf ("failed to unmarshal params: %w" , err )
562+ }
563+ }
564+
565+ // Create the MCP request
566+ mcpRequest := mcp.ElicitationRequest {
567+ Request : mcp.Request {
568+ Method : string (mcp .MethodElicitationCreate ),
569+ },
570+ Params : params ,
571+ }
572+
573+ // Call the elicitation handler
574+ result , err := c .elicitationHandler .Elicit (ctx , mcpRequest )
575+ if err != nil {
576+ return nil , err
577+ }
578+
579+ // Marshal the result
580+ resultBytes , err := json .Marshal (result )
581+ if err != nil {
582+ return nil , fmt .Errorf ("failed to marshal result: %w" , err )
583+ }
584+
585+ // Create the transport response
586+ response := transport .NewJSONRPCResultResponse (request .ID , resultBytes )
587+
525588 return response , nil
526589}
590+
591+ func (c * Client ) handlePingRequestTransport (ctx context.Context , request transport.JSONRPCRequest ) (* transport.JSONRPCResponse , error ) {
592+ b , _ := json .Marshal (& mcp.EmptyResult {})
593+ return transport .NewJSONRPCResultResponse (request .ID , b ), nil
594+ }
595+
527596func listByPage [T any ](
528597 ctx context.Context ,
529598 client * Client ,
0 commit comments