Skip to content

Commit 64a3659

Browse files
author
Mohammed Aboullaite
committed
Stamp default ttlMs and cacheScope on server responses (SEP-2549)
The draft spec requires cacheable results to carry ttlMs and cacheScope on the wire. Other SDKs (Go, Python, TypeScript) all stamp defaults after handlers return: ttlMs=0 (immediately stale) and cacheScope=public. This adds the same default stamping in McpAsyncServer and McpStatelessAsyncServer for all five cacheable result types. For list results the defaults are set at the build site. For ReadResourceResult, which is built by user handlers, a withCacheDefaults helper stamps missing fields while preserving any values the handler set explicitly.
1 parent 1c25b7c commit 64a3659

2 files changed

Lines changed: 58 additions & 10 deletions

File tree

mcp-core/src/main/java/io/modelcontextprotocol/server/McpAsyncServer.java

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,10 @@ private McpRequestHandler<McpSchema.ListToolsResult> toolsListRequestHandler() {
539539
return (exchange, params) -> {
540540
List<Tool> tools = this.tools.stream().map(McpServerFeatures.AsyncToolSpecification::tool).toList();
541541

542-
return Mono.just(McpSchema.ListToolsResult.builder(tools).build());
542+
return Mono.just(McpSchema.ListToolsResult.builder(tools)
543+
.ttlMs(0)
544+
.cacheScope(McpSchema.CacheScope.PUBLIC)
545+
.build());
543546
};
544547
}
545548

@@ -791,7 +794,10 @@ private McpRequestHandler<McpSchema.ListResourcesResult> resourcesListRequestHan
791794
.stream()
792795
.map(McpServerFeatures.AsyncResourceSpecification::resource)
793796
.toList();
794-
return Mono.just(McpSchema.ListResourcesResult.builder(resourceList).build());
797+
return Mono.just(McpSchema.ListResourcesResult.builder(resourceList)
798+
.ttlMs(0)
799+
.cacheScope(McpSchema.CacheScope.PUBLIC)
800+
.build());
795801
};
796802
}
797803

@@ -801,7 +807,10 @@ private McpRequestHandler<McpSchema.ListResourceTemplatesResult> resourceTemplat
801807
.stream()
802808
.map(McpServerFeatures.AsyncResourceTemplateSpecification::resourceTemplate)
803809
.toList();
804-
return Mono.just(McpSchema.ListResourceTemplatesResult.builder(resourceList).build());
810+
return Mono.just(McpSchema.ListResourceTemplatesResult.builder(resourceList)
811+
.ttlMs(0)
812+
.cacheScope(McpSchema.CacheScope.PUBLIC)
813+
.build());
805814
};
806815
}
807816

@@ -822,10 +831,22 @@ private McpRequestHandler<McpSchema.ReadResourceResult> resourcesReadRequestHand
822831
return this.findResourceTemplateSpecification(resourceUri)
823832
.map(spec -> spec.readHandler().apply(ex, resourceRequest))
824833
.orElseGet(() -> Mono.error(RESOURCE_NOT_FOUND.apply(resourceUri)));
825-
});
834+
})
835+
.map(McpAsyncServer::withCacheDefaults);
826836
};
827837
}
828838

839+
private static McpSchema.ReadResourceResult withCacheDefaults(McpSchema.ReadResourceResult result) {
840+
if (result.ttlMs() == null || result.cacheScope() == null) {
841+
return McpSchema.ReadResourceResult.builder(result.contents())
842+
.meta(result.meta())
843+
.ttlMs(result.ttlMs() != null ? result.ttlMs() : 0)
844+
.cacheScope(result.cacheScope() != null ? result.cacheScope() : McpSchema.CacheScope.PUBLIC)
845+
.build();
846+
}
847+
return result;
848+
}
849+
829850
private Optional<McpServerFeatures.AsyncResourceSpecification> findResourceSpecification(String uri) {
830851
var result = this.resources.values()
831852
.stream()
@@ -952,7 +973,10 @@ private McpRequestHandler<McpSchema.ListPromptsResult> promptsListRequestHandler
952973
.map(McpServerFeatures.AsyncPromptSpecification::prompt)
953974
.toList();
954975

955-
return Mono.just(McpSchema.ListPromptsResult.builder(promptList).build());
976+
return Mono.just(McpSchema.ListPromptsResult.builder(promptList)
977+
.ttlMs(0)
978+
.cacheScope(McpSchema.CacheScope.PUBLIC)
979+
.build());
956980
};
957981
}
958982

mcp-core/src/main/java/io/modelcontextprotocol/server/McpStatelessAsyncServer.java

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,10 @@ private McpStatelessRequestHandler<McpSchema.ListToolsResult> toolsListRequestHa
420420
List<Tool> tools = this.tools.stream()
421421
.map(McpStatelessServerFeatures.AsyncToolSpecification::tool)
422422
.toList();
423-
return Mono.just(McpSchema.ListToolsResult.builder(tools).build());
423+
return Mono.just(McpSchema.ListToolsResult.builder(tools)
424+
.ttlMs(0)
425+
.cacheScope(McpSchema.CacheScope.PUBLIC)
426+
.build());
424427
};
425428
}
426429

@@ -584,7 +587,10 @@ private McpStatelessRequestHandler<McpSchema.ListResourcesResult> resourcesListR
584587
.stream()
585588
.map(McpStatelessServerFeatures.AsyncResourceSpecification::resource)
586589
.toList();
587-
return Mono.just(McpSchema.ListResourcesResult.builder(resourceList).build());
590+
return Mono.just(McpSchema.ListResourcesResult.builder(resourceList)
591+
.ttlMs(0)
592+
.cacheScope(McpSchema.CacheScope.PUBLIC)
593+
.build());
588594
};
589595
}
590596

@@ -594,7 +600,10 @@ private McpStatelessRequestHandler<McpSchema.ListResourceTemplatesResult> resour
594600
.stream()
595601
.map(AsyncResourceTemplateSpecification::resourceTemplate)
596602
.toList();
597-
return Mono.just(McpSchema.ListResourceTemplatesResult.builder(resourceList).build());
603+
return Mono.just(McpSchema.ListResourceTemplatesResult.builder(resourceList)
604+
.ttlMs(0)
605+
.cacheScope(McpSchema.CacheScope.PUBLIC)
606+
.build());
598607
};
599608
}
600609

@@ -614,11 +623,23 @@ private McpStatelessRequestHandler<McpSchema.ReadResourceResult> resourcesReadRe
614623
return this.findResourceTemplateSpecification(resourceUri)
615624
.map(spec -> spec.readHandler().apply(ctx, resourceRequest))
616625
.orElseGet(() -> Mono.error(RESOURCE_NOT_FOUND.apply(resourceUri)));
617-
});
626+
})
627+
.map(McpStatelessAsyncServer::withCacheDefaults);
618628

619629
};
620630
}
621631

632+
private static McpSchema.ReadResourceResult withCacheDefaults(McpSchema.ReadResourceResult result) {
633+
if (result.ttlMs() == null || result.cacheScope() == null) {
634+
return McpSchema.ReadResourceResult.builder(result.contents())
635+
.meta(result.meta())
636+
.ttlMs(result.ttlMs() != null ? result.ttlMs() : 0)
637+
.cacheScope(result.cacheScope() != null ? result.cacheScope() : McpSchema.CacheScope.PUBLIC)
638+
.build();
639+
}
640+
return result;
641+
}
642+
622643
private Optional<McpStatelessServerFeatures.AsyncResourceSpecification> findResourceSpecification(String uri) {
623644
var result = this.resources.values()
624645
.stream()
@@ -714,7 +735,10 @@ private McpStatelessRequestHandler<McpSchema.ListPromptsResult> promptsListReque
714735
.map(McpStatelessServerFeatures.AsyncPromptSpecification::prompt)
715736
.toList();
716737

717-
return Mono.just(McpSchema.ListPromptsResult.builder(promptList).build());
738+
return Mono.just(McpSchema.ListPromptsResult.builder(promptList)
739+
.ttlMs(0)
740+
.cacheScope(McpSchema.CacheScope.PUBLIC)
741+
.build());
718742
};
719743
}
720744

0 commit comments

Comments
 (0)