@@ -173,10 +173,18 @@ public ValueTask<PingResult> PingAsync(
173173 /// <returns>A list of all available tools as <see cref="McpClientTool"/> instances.</returns>
174174 /// <exception cref="McpException">The request failed or the server returned an error response.</exception>
175175 /// <remarks>
176+ /// <para>
176177 /// This overload aggregates every page into a single list and does not surface the per-result caching hints
177178 /// (<see cref="ListToolsResult.TimeToLive"/> and <see cref="ListToolsResult.CacheScope"/>). To read those hints,
178179 /// use the <see cref="ListToolsAsync(ListToolsRequestParams, CancellationToken)"/> overload, which returns the
179180 /// raw <see cref="ListToolsResult"/> for each page.
181+ /// </para>
182+ /// <para>
183+ /// The SDK does not perform any internal caching of listing results; every call re-fetches all pages from the server.
184+ /// If you want to cache listing results, do so in your own code using the lower-level
185+ /// <see cref="ListToolsAsync(ListToolsRequestParams, CancellationToken)"/> overload, which exposes the per-page
186+ /// caching hints and lets you manage pagination so each page can be cached and expired independently.
187+ /// </para>
180188 /// </remarks>
181189 public async ValueTask < IList < McpClientTool > > ListToolsAsync (
182190 RequestOptions ? options = null ,
@@ -247,12 +255,25 @@ public ValueTask<ListToolsResult> ListToolsAsync(
247255 {
248256 Throw . IfNull ( requestParams ) ;
249257
250- return SendRequestAsync (
258+ return ValidateCacheableResultAsync ( RequestMethods . ToolsList , SendRequestAsync (
251259 RequestMethods . ToolsList ,
252260 requestParams ,
253261 McpJsonUtilities . JsonContext . Default . ListToolsRequestParams ,
254262 McpJsonUtilities . JsonContext . Default . ListToolsResult ,
255- cancellationToken : cancellationToken ) ;
263+ cancellationToken : cancellationToken ) ) ;
264+ }
265+
266+ /// <summary>
267+ /// Awaits a cacheable result and gives derived clients a chance to emit diagnostics (for example, a
268+ /// SEP-2549 conformance warning) before returning it. Preserves the synchronous argument validation
269+ /// performed by the callers before the request is issued.
270+ /// </summary>
271+ private async ValueTask < TResult > ValidateCacheableResultAsync < TResult > ( string method , ValueTask < TResult > resultTask )
272+ where TResult : ICacheableResult
273+ {
274+ var result = await resultTask . ConfigureAwait ( false ) ;
275+ ValidateCacheableResult ( method , result ) ;
276+ return result ;
256277 }
257278
258279 /// <summary>
@@ -263,10 +284,18 @@ public ValueTask<ListToolsResult> ListToolsAsync(
263284 /// <returns>A list of all available prompts as <see cref="McpClientPrompt"/> instances.</returns>
264285 /// <exception cref="McpException">The request failed or the server returned an error response.</exception>
265286 /// <remarks>
287+ /// <para>
266288 /// This overload aggregates every page into a single list and does not surface the per-result caching hints
267289 /// (<see cref="ListPromptsResult.TimeToLive"/> and <see cref="ListPromptsResult.CacheScope"/>). To read those hints,
268290 /// use the <see cref="ListPromptsAsync(ListPromptsRequestParams, CancellationToken)"/> overload, which returns the
269291 /// raw <see cref="ListPromptsResult"/> for each page.
292+ /// </para>
293+ /// <para>
294+ /// The SDK does not perform any internal caching of listing results; every call re-fetches all pages from the server.
295+ /// If you want to cache listing results, do so in your own code using the lower-level
296+ /// <see cref="ListPromptsAsync(ListPromptsRequestParams, CancellationToken)"/> overload, which exposes the per-page
297+ /// caching hints and lets you manage pagination so each page can be cached and expired independently.
298+ /// </para>
270299 /// </remarks>
271300 public async ValueTask < IList < McpClientPrompt > > ListPromptsAsync (
272301 RequestOptions ? options = null ,
@@ -309,12 +338,12 @@ public ValueTask<ListPromptsResult> ListPromptsAsync(
309338 {
310339 Throw . IfNull ( requestParams ) ;
311340
312- return SendRequestAsync (
341+ return ValidateCacheableResultAsync ( RequestMethods . PromptsList , SendRequestAsync (
313342 RequestMethods . PromptsList ,
314343 requestParams ,
315344 McpJsonUtilities . JsonContext . Default . ListPromptsRequestParams ,
316345 McpJsonUtilities . JsonContext . Default . ListPromptsResult ,
317- cancellationToken : cancellationToken ) ;
346+ cancellationToken : cancellationToken ) ) ;
318347 }
319348
320349 /// <summary>
@@ -379,10 +408,18 @@ public ValueTask<GetPromptResult> GetPromptAsync(
379408 /// <returns>A list of all available resource templates as <see cref="ResourceTemplate"/> instances.</returns>
380409 /// <exception cref="McpException">The request failed or the server returned an error response.</exception>
381410 /// <remarks>
411+ /// <para>
382412 /// This overload aggregates every page into a single list and does not surface the per-result caching hints
383413 /// (<see cref="ListResourceTemplatesResult.TimeToLive"/> and <see cref="ListResourceTemplatesResult.CacheScope"/>). To read those hints,
384414 /// use the <see cref="ListResourceTemplatesAsync(ListResourceTemplatesRequestParams, CancellationToken)"/> overload, which returns the
385415 /// raw <see cref="ListResourceTemplatesResult"/> for each page.
416+ /// </para>
417+ /// <para>
418+ /// The SDK does not perform any internal caching of listing results; every call re-fetches all pages from the server.
419+ /// If you want to cache listing results, do so in your own code using the lower-level
420+ /// <see cref="ListResourceTemplatesAsync(ListResourceTemplatesRequestParams, CancellationToken)"/> overload, which exposes the per-page
421+ /// caching hints and lets you manage pagination so each page can be cached and expired independently.
422+ /// </para>
386423 /// </remarks>
387424 public async ValueTask < IList < McpClientResourceTemplate > > ListResourceTemplatesAsync (
388425 RequestOptions ? options = null ,
@@ -425,12 +462,12 @@ public ValueTask<ListResourceTemplatesResult> ListResourceTemplatesAsync(
425462 {
426463 Throw . IfNull ( requestParams ) ;
427464
428- return SendRequestAsync (
465+ return ValidateCacheableResultAsync ( RequestMethods . ResourcesTemplatesList , SendRequestAsync (
429466 RequestMethods . ResourcesTemplatesList ,
430467 requestParams ,
431468 McpJsonUtilities . JsonContext . Default . ListResourceTemplatesRequestParams ,
432469 McpJsonUtilities . JsonContext . Default . ListResourceTemplatesResult ,
433- cancellationToken : cancellationToken ) ;
470+ cancellationToken : cancellationToken ) ) ;
434471 }
435472
436473 /// <summary>
@@ -441,10 +478,18 @@ public ValueTask<ListResourceTemplatesResult> ListResourceTemplatesAsync(
441478 /// <returns>A list of all available resources as <see cref="Resource"/> instances.</returns>
442479 /// <exception cref="McpException">The request failed or the server returned an error response.</exception>
443480 /// <remarks>
481+ /// <para>
444482 /// This overload aggregates every page into a single list and does not surface the per-result caching hints
445483 /// (<see cref="ListResourcesResult.TimeToLive"/> and <see cref="ListResourcesResult.CacheScope"/>). To read those hints,
446484 /// use the <see cref="ListResourcesAsync(ListResourcesRequestParams, CancellationToken)"/> overload, which returns the
447485 /// raw <see cref="ListResourcesResult"/> for each page.
486+ /// </para>
487+ /// <para>
488+ /// The SDK does not perform any internal caching of listing results; every call re-fetches all pages from the server.
489+ /// If you want to cache listing results, do so in your own code using the lower-level
490+ /// <see cref="ListResourcesAsync(ListResourcesRequestParams, CancellationToken)"/> overload, which exposes the per-page
491+ /// caching hints and lets you manage pagination so each page can be cached and expired independently.
492+ /// </para>
448493 /// </remarks>
449494 public async ValueTask < IList < McpClientResource > > ListResourcesAsync (
450495 RequestOptions ? options = null ,
@@ -487,12 +532,12 @@ public ValueTask<ListResourcesResult> ListResourcesAsync(
487532 {
488533 Throw . IfNull ( requestParams ) ;
489534
490- return SendRequestAsync (
535+ return ValidateCacheableResultAsync ( RequestMethods . ResourcesList , SendRequestAsync (
491536 RequestMethods . ResourcesList ,
492537 requestParams ,
493538 McpJsonUtilities . JsonContext . Default . ListResourcesRequestParams ,
494539 McpJsonUtilities . JsonContext . Default . ListResourcesResult ,
495- cancellationToken : cancellationToken ) ;
540+ cancellationToken : cancellationToken ) ) ;
496541 }
497542
498543 /// <summary>
@@ -571,12 +616,12 @@ public ValueTask<ReadResourceResult> ReadResourceAsync(
571616 {
572617 Throw . IfNull ( requestParams ) ;
573618
574- return SendRequestAsync (
619+ return ValidateCacheableResultAsync ( RequestMethods . ResourcesRead , SendRequestAsync (
575620 RequestMethods . ResourcesRead ,
576621 requestParams ,
577622 McpJsonUtilities . JsonContext . Default . ReadResourceRequestParams ,
578623 McpJsonUtilities . JsonContext . Default . ReadResourceResult ,
579- cancellationToken : cancellationToken ) ;
624+ cancellationToken : cancellationToken ) ) ;
580625 }
581626
582627 /// <summary>
0 commit comments