@@ -174,6 +174,14 @@ type ServerOptions struct {
174174 // true, since stateless servers do not maintain sessions.
175175 GetSessionID func () string
176176
177+ // SetCacheable, if non-nil, decides the cache-control fields (ttlMs and
178+ // cacheScope) of every result that carries them: server/discover, the
179+ // four list methods, and resources/read.
180+ //
181+ // It is called once per such result, after the corresponding handler has
182+ // returned, with c holding the values that handler produced.
183+ SetCacheable func (ctx context.Context , req Request , c * Cacheable )
184+
177185 // SupportedProtocolVersions, if non-empty, restricts the protocol versions
178186 // this server advertises. If empty, every version returned by
179187 // [SupportedProtocolVersions] is used.
@@ -870,7 +878,7 @@ func (s *Server) Sessions() iter.Seq[*ServerSession] {
870878 return slices .Values (clients )
871879}
872880
873- func (s * Server ) listPrompts (_ context.Context , req * ListPromptsRequest ) (* ListPromptsResult , error ) {
881+ func (s * Server ) listPrompts (ctx context.Context , req * ListPromptsRequest ) (* ListPromptsResult , error ) {
874882 s .mu .Lock ()
875883 defer s .mu .Unlock ()
876884 if req .Params == nil {
@@ -885,7 +893,7 @@ func (s *Server) listPrompts(_ context.Context, req *ListPromptsRequest) (*ListP
885893 if err != nil {
886894 return nil , err
887895 }
888- res . setDefaultCacheableValues ( )
896+ s . resolveCacheable ( ctx , req , & res . Cacheable )
889897 return res , nil
890898}
891899
@@ -915,7 +923,7 @@ func (s *Server) getPrompt(ctx context.Context, req *GetPromptRequest) (*GetProm
915923// the server's capabilities, the server's identity, and the server's
916924// instructions, allowing clients to negotiate without performing the legacy
917925// initialize handshake.
918- func (s * Server ) discover (_ context.Context , req * ServerRequest [* DiscoverParams ]) (* DiscoverResult , error ) {
926+ func (s * Server ) discover (ctx context.Context , req * ServerRequest [* DiscoverParams ]) (* DiscoverResult , error ) {
919927 req .Session .mu .Lock ()
920928 versions := req .Session .supportedVersions
921929 req .Session .mu .Unlock ()
@@ -947,7 +955,7 @@ func (s *Server) discover(_ context.Context, req *ServerRequest[*DiscoverParams]
947955 Capabilities : s .capabilities (),
948956 Instructions : s .opts .Instructions ,
949957 }
950- res . setDefaultCacheableValues ( )
958+ s . resolveCacheable ( ctx , req , & res . Cacheable )
951959 return res , nil
952960}
953961
@@ -968,7 +976,7 @@ func filterSupportedVersions(t Transport, versions []string) []string {
968976 return out
969977}
970978
971- func (s * Server ) listTools (_ context.Context , req * ListToolsRequest ) (* ListToolsResult , error ) {
979+ func (s * Server ) listTools (ctx context.Context , req * ListToolsRequest ) (* ListToolsResult , error ) {
972980 s .mu .Lock ()
973981 defer s .mu .Unlock ()
974982 if req .Params == nil {
@@ -983,7 +991,7 @@ func (s *Server) listTools(_ context.Context, req *ListToolsRequest) (*ListTools
983991 if err != nil {
984992 return nil , err
985993 }
986- res . setDefaultCacheableValues ( )
994+ s . resolveCacheable ( ctx , req , & res . Cacheable )
987995 return res , nil
988996}
989997
@@ -1016,7 +1024,7 @@ func (s *Server) callTool(ctx context.Context, req *CallToolRequest) (*CallToolR
10161024 return res , err
10171025}
10181026
1019- func (s * Server ) listResources (_ context.Context , req * ListResourcesRequest ) (* ListResourcesResult , error ) {
1027+ func (s * Server ) listResources (ctx context.Context , req * ListResourcesRequest ) (* ListResourcesResult , error ) {
10201028 s .mu .Lock ()
10211029 defer s .mu .Unlock ()
10221030 if req .Params == nil {
@@ -1031,11 +1039,11 @@ func (s *Server) listResources(_ context.Context, req *ListResourcesRequest) (*L
10311039 if err != nil {
10321040 return nil , err
10331041 }
1034- res . setDefaultCacheableValues ( )
1042+ s . resolveCacheable ( ctx , req , & res . Cacheable )
10351043 return res , nil
10361044}
10371045
1038- func (s * Server ) listResourceTemplates (_ context.Context , req * ListResourceTemplatesRequest ) (* ListResourceTemplatesResult , error ) {
1046+ func (s * Server ) listResourceTemplates (ctx context.Context , req * ListResourceTemplatesRequest ) (* ListResourceTemplatesResult , error ) {
10391047 s .mu .Lock ()
10401048 defer s .mu .Unlock ()
10411049 if req .Params == nil {
@@ -1051,7 +1059,7 @@ func (s *Server) listResourceTemplates(_ context.Context, req *ListResourceTempl
10511059 if err != nil {
10521060 return nil , err
10531061 }
1054- res . setDefaultCacheableValues ( )
1062+ s . resolveCacheable ( ctx , req , & res . Cacheable )
10551063 return res , nil
10561064}
10571065
@@ -1075,7 +1083,7 @@ func (s *Server) readResource(ctx context.Context, req *ReadResourceRequest) (*R
10751083 if err := handleMultiRoundTripResult (req .Session , s .opts .Logger , res ); err != nil {
10761084 return nil , err
10771085 }
1078- res . setDefaultCacheableValues ( )
1086+ s . resolveCacheable ( ctx , req , & res . Cacheable )
10791087 if res .resultType == resultTypeInputRequired {
10801088 return res , nil
10811089 }
@@ -1094,6 +1102,22 @@ func (s *Server) readResource(ctx context.Context, req *ReadResourceRequest) (*R
10941102 return res , nil
10951103}
10961104
1105+ // resolveCacheable settles the cache-control fields of an outgoing result.
1106+ //
1107+ // On entry c holds whatever the feature handler produced, which is the zero
1108+ // value for results the SDK builds itself. [ServerOptions.SetCacheable] may
1109+ // then rewrite it, and any cacheScope still unset is filled with the protocol
1110+ // default.
1111+ //
1112+ // The list methods call this with s.mu held, so SetCacheable must not call
1113+ // back into the server; see its documentation.
1114+ func (s * Server ) resolveCacheable (ctx context.Context , req Request , c * Cacheable ) {
1115+ if s .opts .SetCacheable != nil {
1116+ s .opts .SetCacheable (ctx , req , c )
1117+ }
1118+ c .normalize ()
1119+ }
1120+
10971121// lookupResourceHandler returns the resource handler and MIME type for the resource or
10981122// resource template matching uri. If none, the last return value is false.
10991123func (s * Server ) lookupResourceHandler (uri string ) (ResourceHandler , string , bool ) {
0 commit comments