@@ -89,6 +89,10 @@ type ServerOptions struct {
8989 // even if no tools have been registered.
9090 HasTools bool
9191
92+ // ProtocolVersion is the version of the protocol to use.
93+ // If empty, it defaults to the latest version.
94+ ProtocolVersion string
95+
9296 // GetSessionID provides the next session ID to use for an incoming request.
9397 // If nil, a default randomly generated ID will be used.
9498 //
@@ -980,6 +984,18 @@ func (ss *ServerSession) ID() string {
980984 return ""
981985}
982986
987+ func (ss * ServerSession ) ProtocolVersion () string {
988+ protocolVersion := ss .server .opts .ProtocolVersion
989+ if protocolVersion == "" {
990+ return latestProtocolVersion
991+ }
992+ return protocolVersion
993+ }
994+
995+ func (ss * ServerSession ) setProtocolVersion (v string ) {
996+ ss .server .opts .ProtocolVersion = v
997+ }
998+
983999// Ping pings the client.
9841000func (ss * ServerSession ) Ping (ctx context.Context , params * PingParams ) error {
9851001 _ , err := handleSend [* emptyResult ](ctx , methodPing , newServerRequest (ss , orZero [Params ](params )))
@@ -1086,6 +1102,7 @@ var serverMethodInfos = map[string]methodInfo{
10861102 methodSetLevel : newServerMethodInfo (serverSessionMethod ((* ServerSession ).setLevel ), 0 ),
10871103 methodSubscribe : newServerMethodInfo (serverMethod ((* Server ).subscribe ), 0 ),
10881104 methodUnsubscribe : newServerMethodInfo (serverMethod ((* Server ).unsubscribe ), 0 ),
1105+ methodServerDiscover : newServerMethodInfo (serverSessionMethod ((* ServerSession ).discover ), missingParamsOK ),
10891106 notificationCancelled : newServerMethodInfo (serverSessionMethod ((* ServerSession ).cancel ), notification | missingParamsOK ),
10901107 notificationInitialized : newServerMethodInfo (serverSessionMethod ((* ServerSession ).initialized ), notification | missingParamsOK ),
10911108 notificationRootsListChanged : newServerMethodInfo (serverMethod ((* Server ).callRootsListChangedHandler ), notification | missingParamsOK ),
@@ -1117,17 +1134,23 @@ func (ss *ServerSession) getConn() *jsonrpc2.Connection { return ss.conn }
11171134func (ss * ServerSession ) handle (ctx context.Context , req * jsonrpc.Request ) (any , error ) {
11181135 ss .mu .Lock ()
11191136 initialized := ss .state .InitializeParams != nil
1137+ protocolVersion := ss .server .opts .ProtocolVersion
1138+ if protocolVersion == "" {
1139+ protocolVersion = latestProtocolVersion
1140+ }
11201141 ss .mu .Unlock ()
11211142
11221143 // From the spec:
11231144 // "The client SHOULD NOT send requests other than pings before the server
11241145 // has responded to the initialize request."
1125- switch req .Method {
1126- case methodInitialize , methodPing , notificationInitialized :
1127- default :
1128- if ! initialized {
1129- ss .server .opts .Logger .Error ("method invalid during initialization" , "method" , req .Method )
1130- return nil , fmt .Errorf ("method %q is invalid during session initialization" , req .Method )
1146+ if compareProtocolVersions (protocolVersion , protocolVersion20251130 ) < 0 {
1147+ switch req .Method {
1148+ case methodInitialize , methodPing , notificationInitialized :
1149+ default :
1150+ if ! initialized {
1151+ ss .server .opts .Logger .Error ("method invalid during initialization" , "method" , req .Method )
1152+ return nil , fmt .Errorf ("method %q is invalid during session initialization" , req .Method )
1153+ }
11311154 }
11321155 }
11331156
@@ -1154,21 +1177,46 @@ func (ss *ServerSession) InitializeParams() *InitializeParams {
11541177}
11551178
11561179func (ss * ServerSession ) initialize (ctx context.Context , params * InitializeParams ) (* InitializeResult , error ) {
1157- if params == nil {
1158- return nil , fmt .Errorf ("%w: \" params\" must be be provided" , jsonrpc2 .ErrInvalidParams )
1180+ protocolVersion := ss .server .opts .ProtocolVersion
1181+ if protocolVersion == "" {
1182+ protocolVersion = latestProtocolVersion
1183+ }
1184+
1185+ // For older protocol versions, the initialize handshake is required.
1186+ if compareProtocolVersions (protocolVersion , protocolVersion20251130 ) < 0 {
1187+ if params == nil {
1188+ return nil , fmt .Errorf ("%w: \" params\" must be be provided" , jsonrpc2 .ErrInvalidParams )
1189+ }
1190+ ss .updateState (func (state * ServerSessionState ) {
1191+ state .InitializeParams = params
1192+ })
1193+ } else {
1194+ // For protocol versions >= 2025-11-30, the initialize handshake is optional.
1195+ // If params are provided, we process them.
1196+ if params != nil {
1197+ ss .updateState (func (state * ServerSessionState ) {
1198+ state .InitializeParams = params
1199+ })
1200+ }
11591201 }
1160- ss .updateState (func (state * ServerSessionState ) {
1161- state .InitializeParams = params
1162- })
11631202
11641203 s := ss .server
11651204 return & InitializeResult {
1166- // TODO(rfindley): alter behavior when falling back to an older version:
1167- // reject unsupported features.
11681205 ProtocolVersion : negotiatedVersion (params .ProtocolVersion ),
11691206 Capabilities : s .capabilities (),
11701207 Instructions : s .opts .Instructions ,
11711208 ServerInfo : s .impl ,
1209+ SessionID : ss .ID (),
1210+ }, nil
1211+ }
1212+
1213+ func (ss * ServerSession ) discover (ctx context.Context , req * DiscoverParams ) (* DiscoverResult , error ) {
1214+ s := ss .server
1215+ return & DiscoverResult {
1216+ ProtocolVersion : ss .ProtocolVersion (),
1217+ ServerInfo : s .impl ,
1218+ Capabilities : s .capabilities (),
1219+ Instructions : s .opts .Instructions ,
11721220 }, nil
11731221}
11741222
0 commit comments