modelcontextprotocol / modelcontextprotocol/kotlin-sdk
[Proposal] SEP-2549: TTL for List Results implementation design (#813)
Nobody has claimed this yet.
- Dominant language
- Kotlin
- Stars
- 1.5k
- Forks
- 248
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 23
Description
Proposal: SEP-2549 TTL for List Results Implementation Design (#813)
Motivation & Context
Tracking implementation of SEP-2549 in kotlin-sdk for the 2026-07-28 MCP specification release (aligned with umbrella issue #842).
SEP-2549 introduces response caching capabilities for list operations (tools/list, resources/list, resources/templates/list, prompts/list, and resources/read). This significantly reduces transport round-trips and polling overhead for static or slow-changing server surfaces while preserving real-time invalidation via existing list-changed notifications.
Key wire-level fields introduced by SEP-2549:
ttlMs: Long?: Time-to-live in milliseconds that a client may treat the result as fresh.cacheScope: String?: Scope of caching ("public"or"private"). Defaults to"private"ifttlMsis set butcacheScopeis omitted.
This proposal outlines the Kotlin Multiplatform architecture for implementing SEP-2549 in kotlin-sdk-core, kotlin-sdk-client, and kotlin-sdk-server.
Proposed Architecture & Component Design
1. Protocol Types & Enums (kotlin-sdk-core)
In kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/:
- Introduce a type-safe
CacheScopeenum incommon.kt:@Serializable public enum class CacheScope(public val value: String) { @SerialName("public") PUBLIC("public"), @SerialName("private") PRIVATE("private"); } - Define a shared interface for cacheable results:
public sealed interface WithCacheControl { public val ttlMs: Long? public val cacheScope: CacheScope? } - Update result data classes (
ListToolsResult,ListResourcesResult,ListResourceTemplatesResult,ListPromptsResult,ReadResourceResult) to implementWithCacheControl:@Serializable public data class ListToolsResult( val tools: List<Tool>, val nextCursor: String? = null, override val _meta: JsonObject? = null, @SerialName("ttlMs") override val ttlMs: Long? = null, @SerialName("cacheScope") override val cacheScope: CacheScope? = null, ) : ServerResult, PaginatedResult, WithCacheControl - Add wire validation:
- Negative
ttlMsvalues should be rejected or clamped to0Lduring deserialization/construction. - Omitted or blank
cacheScopegracefully resolves tonullon the wire, falling back to client-sidePRIVATEinterpretation whenttlMs != null.
- Negative
2. Client-Side Caching Layer (kotlin-sdk-client)
In kotlin-sdk-client:
- Add a client-side memory cache contract:
public interface McpResultCache { public suspend fun <T : WithCacheControl> get(key: String): T? public suspend fun <T : WithCacheControl> put(key: String, result: T) public suspend fun invalidate(pattern: String) public suspend fun clear() } - Transparent Cache Integration:
- When
client.listTools(),client.listResources(), etc., are invoked, the client checksMcpResultCache. - If a cached response exists and
now < cachedAt + ttlMs, return the cached instance without network I/O. - Automatically invalidate cached tool/resource/prompt buckets when corresponding server notifications arrive:
notifications/tools/list_changed-> invalidatetools/*notifications/resources/list_changed-> invalidateresources/*notifications/prompts/list_changed-> invalidateprompts/*
- When
3. Server-Side Ergonomics (kotlin-sdk-server)
In kotlin-sdk-server:
- Enable servers to attach caching hints declaratively:
server.addTool( name = "calculate", description = "Perform calculation", inputSchema = schema, cacheControl = CacheControl(ttlMs = 300_000L, scope = CacheScope.PUBLIC) ) { args -> ... } - Or provide an overload on server response builders allowing handlers to set
ttlMsandcacheScopebased on whether the data is user-scoped or system-wide.
4. Backward Compatibility & Testing
- Fully backward-compatible:
ttlMsandcacheScopedefault tonull, producing identical wire JSON for older protocol versions. - Unit and Conformance Tests:
- Serializer round-trip tests for
ttlMsandcacheScope(both present,ttlMsalone, neither present). - Client cache hit/miss behavior within and after TTL expiry.
- Cache eviction verification upon receiving
tools/list_changednotifications.
- Serializer round-trip tests for
Next Steps
Upon maintainer review and consensus on the component design, we are ready to submit an initial PR implementing the kotlin-sdk-core schema fields and serialization tests.
AI assistance disclosure: AI was used to discover this opportunity and draft the change or text. The submission was checked against the prepared artifact and recorded verification evidence.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/common.kt and the listed result data classes to review the protocol fields and serialization conventions. Then inspect kotlin-sdk-client and kotlin-sdk-server entry points and existing tests for list operations and notifications. Done means maintainer consensus on the architecture and a tested initial implementation covering the stated compatibility and cache behaviors.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- kotlin
- Domain
- backend-api-design, performance
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100