add CacheableResult from protocol 2026-07-28 - #570
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces the CacheableResult extension type and the CacheScope enum to support caching hints (ttlMs and cacheScope) defined in the 2026-07-28 draft schema. Multiple result types have been updated to implement CacheableResult, and corresponding unit tests have been added. Feedback suggests optimizing the cacheScope getter by checking for a null value before iterating over the enum values to avoid unnecessary overhead.
SEP-2549 states both that cacheScope defaults to public when absent and that the field is required because there is no safe default for older servers, and it leaves the choice to each SDK. The doc claimed the spec defines no default, which contradicts the first half. Spell out the conflict and why null is the safe reading: synthesizing public for a server that never declared a scope is the one guess that can leak a private response into a shared cache.
|
@Yusufihsangorgel note that I will be out of office until Thursday, so I won't be able to review additional PRs until then. If they are relatively unrelated though you can stack up multiple at once and I will review them all when I get back. |
|
Thanks for landing this one. I'll line up the next transport slices so they're ready when you're back. Enjoy the time off. |
Next 2026-07-28 core-protocol slice tracked in #162, following #565 and kept separate from the HTTP transport work.
Adds the
CacheableResult"mixin" extension type and theCacheScopeenum, modeling the caching hints from modelcontextprotocol/modelcontextprotocol#2549:CacheableResult.ttlMsreads the TTL hint as anint. The spec requires servers to sendttlMs >= 0and tells clients to treat both an absent value and a negative one as0(https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/draft/server/utilities/caching.mdx; servers on earlier protocol versions never send the field), so the getter reads0for both. Same foldResult.resultTypedoes withcomplete.CacheableResult.cacheScopereads the scope as a nullableCacheScope. The schema types the field as a closed"public" | "private"union with no absent-value default, so the getter is an enum like the package's other closed unions (Role,LoggingLevel) but resolves the waySchema.typedoes: an absent or unrecognized value reads asnullinstead of throwing, which keeps results from older servers readable and leaves room for the still-draft schema to grow the union before the RC.PaginatedResult: no public constructor, "mixed in" by other extension types. The schema attaches it to the four list results,ReadResourceResult, and the newDiscoverResult; the five that already exist in this package now implement it, so the hints are readable on the results the client API already returns.DiscoverResultitself and server-side emission of the hints (factory parameters) are follow-up slices.Tests
ttlMsreads0on an empty result and for a negative value,cacheScopereadsnullwhen absent, both parse when present, an unrecognized scope string reads asnull, and aListToolsResultcarrying the fields exposes both.dart test -p chrome,vm -c dart2wasm,dart2js,kernel,exepasses (220 tests in each of the four configurations).dart analyze --fatal-infosis clean here and inmcp_examplesresolved against this branch.Part of #162.