Skip to content

Commit f57fa06

Browse files
author
Mohammed Aboullaite
committed
Use Long for ttlMs and default resources/read scope to PRIVATE
Two fixes from review: 1. Widen ttlMs from Integer to Long across all five cacheable result records. The spec defines ttlMs as a non-negative integer with no upper bound, and Jackson rejects values exceeding Integer.MAX_VALUE. Long handles any realistic TTL without interop failures. 2. Default cacheScope to PRIVATE (not PUBLIC) for resources/read in both server classes. The spec's caching guidance says resources/read results that depend on the authenticated user should be private. List results keep the PUBLIC default since they are not user-specific.
1 parent 64a3659 commit f57fa06

4 files changed

Lines changed: 46 additions & 46 deletions

File tree

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

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

542542
return Mono.just(McpSchema.ListToolsResult.builder(tools)
543-
.ttlMs(0)
543+
.ttlMs(0L)
544544
.cacheScope(McpSchema.CacheScope.PUBLIC)
545545
.build());
546546
};
@@ -795,7 +795,7 @@ private McpRequestHandler<McpSchema.ListResourcesResult> resourcesListRequestHan
795795
.map(McpServerFeatures.AsyncResourceSpecification::resource)
796796
.toList();
797797
return Mono.just(McpSchema.ListResourcesResult.builder(resourceList)
798-
.ttlMs(0)
798+
.ttlMs(0L)
799799
.cacheScope(McpSchema.CacheScope.PUBLIC)
800800
.build());
801801
};
@@ -808,7 +808,7 @@ private McpRequestHandler<McpSchema.ListResourceTemplatesResult> resourceTemplat
808808
.map(McpServerFeatures.AsyncResourceTemplateSpecification::resourceTemplate)
809809
.toList();
810810
return Mono.just(McpSchema.ListResourceTemplatesResult.builder(resourceList)
811-
.ttlMs(0)
811+
.ttlMs(0L)
812812
.cacheScope(McpSchema.CacheScope.PUBLIC)
813813
.build());
814814
};
@@ -840,8 +840,8 @@ private static McpSchema.ReadResourceResult withCacheDefaults(McpSchema.ReadReso
840840
if (result.ttlMs() == null || result.cacheScope() == null) {
841841
return McpSchema.ReadResourceResult.builder(result.contents())
842842
.meta(result.meta())
843-
.ttlMs(result.ttlMs() != null ? result.ttlMs() : 0)
844-
.cacheScope(result.cacheScope() != null ? result.cacheScope() : McpSchema.CacheScope.PUBLIC)
843+
.ttlMs(result.ttlMs() != null ? result.ttlMs() : 0L)
844+
.cacheScope(result.cacheScope() != null ? result.cacheScope() : McpSchema.CacheScope.PRIVATE)
845845
.build();
846846
}
847847
return result;
@@ -974,7 +974,7 @@ private McpRequestHandler<McpSchema.ListPromptsResult> promptsListRequestHandler
974974
.toList();
975975

976976
return Mono.just(McpSchema.ListPromptsResult.builder(promptList)
977-
.ttlMs(0)
977+
.ttlMs(0L)
978978
.cacheScope(McpSchema.CacheScope.PUBLIC)
979979
.build());
980980
};

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ private McpStatelessRequestHandler<McpSchema.ListToolsResult> toolsListRequestHa
421421
.map(McpStatelessServerFeatures.AsyncToolSpecification::tool)
422422
.toList();
423423
return Mono.just(McpSchema.ListToolsResult.builder(tools)
424-
.ttlMs(0)
424+
.ttlMs(0L)
425425
.cacheScope(McpSchema.CacheScope.PUBLIC)
426426
.build());
427427
};
@@ -588,7 +588,7 @@ private McpStatelessRequestHandler<McpSchema.ListResourcesResult> resourcesListR
588588
.map(McpStatelessServerFeatures.AsyncResourceSpecification::resource)
589589
.toList();
590590
return Mono.just(McpSchema.ListResourcesResult.builder(resourceList)
591-
.ttlMs(0)
591+
.ttlMs(0L)
592592
.cacheScope(McpSchema.CacheScope.PUBLIC)
593593
.build());
594594
};
@@ -601,7 +601,7 @@ private McpStatelessRequestHandler<McpSchema.ListResourceTemplatesResult> resour
601601
.map(AsyncResourceTemplateSpecification::resourceTemplate)
602602
.toList();
603603
return Mono.just(McpSchema.ListResourceTemplatesResult.builder(resourceList)
604-
.ttlMs(0)
604+
.ttlMs(0L)
605605
.cacheScope(McpSchema.CacheScope.PUBLIC)
606606
.build());
607607
};
@@ -633,8 +633,8 @@ private static McpSchema.ReadResourceResult withCacheDefaults(McpSchema.ReadReso
633633
if (result.ttlMs() == null || result.cacheScope() == null) {
634634
return McpSchema.ReadResourceResult.builder(result.contents())
635635
.meta(result.meta())
636-
.ttlMs(result.ttlMs() != null ? result.ttlMs() : 0)
637-
.cacheScope(result.cacheScope() != null ? result.cacheScope() : McpSchema.CacheScope.PUBLIC)
636+
.ttlMs(result.ttlMs() != null ? result.ttlMs() : 0L)
637+
.cacheScope(result.cacheScope() != null ? result.cacheScope() : McpSchema.CacheScope.PRIVATE)
638638
.build();
639639
}
640640
return result;
@@ -736,7 +736,7 @@ private McpStatelessRequestHandler<McpSchema.ListPromptsResult> promptsListReque
736736
.toList();
737737

738738
return Mono.just(McpSchema.ListPromptsResult.builder(promptList)
739-
.ttlMs(0)
739+
.ttlMs(0L)
740740
.cacheScope(McpSchema.CacheScope.PUBLIC)
741741
.build());
742742
};

mcp-core/src/main/java/io/modelcontextprotocol/spec/McpSchema.java

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1629,7 +1629,7 @@ public record ListResourcesResult( // @formatter:off
16291629
@JsonProperty("resources") List<Resource> resources,
16301630
@JsonProperty("nextCursor") String nextCursor,
16311631
@JsonProperty("_meta") Map<String, Object> meta,
1632-
@JsonProperty("ttlMs") Integer ttlMs,
1632+
@JsonProperty("ttlMs") Long ttlMs,
16331633
@JsonProperty("cacheScope") CacheScope cacheScope) implements Result { // @formatter:on
16341634

16351635
public ListResourcesResult {
@@ -1639,7 +1639,7 @@ public record ListResourcesResult( // @formatter:off
16391639
@JsonCreator
16401640
static ListResourcesResult fromJson(@JsonProperty("resources") List<Resource> resources,
16411641
@JsonProperty("nextCursor") String nextCursor, @JsonProperty("_meta") Map<String, Object> meta,
1642-
@JsonProperty("ttlMs") Integer ttlMs, @JsonProperty("cacheScope") CacheScope cacheScope) {
1642+
@JsonProperty("ttlMs") Long ttlMs, @JsonProperty("cacheScope") CacheScope cacheScope) {
16431643
if (resources == null) {
16441644
logger.warn(
16451645
"ListResourcesResult: missing required field 'resources' during deserialization, using default []");
@@ -1670,7 +1670,7 @@ public static class Builder {
16701670

16711671
private Map<String, Object> meta;
16721672

1673-
private Integer ttlMs;
1673+
private Long ttlMs;
16741674

16751675
private CacheScope cacheScope;
16761676

@@ -1689,7 +1689,7 @@ public Builder meta(Map<String, Object> meta) {
16891689
return this;
16901690
}
16911691

1692-
public Builder ttlMs(Integer ttlMs) {
1692+
public Builder ttlMs(Long ttlMs) {
16931693
this.ttlMs = ttlMs;
16941694
return this;
16951695
}
@@ -1723,7 +1723,7 @@ public record ListResourceTemplatesResult( // @formatter:off
17231723
@JsonProperty("resourceTemplates") List<ResourceTemplate> resourceTemplates,
17241724
@JsonProperty("nextCursor") String nextCursor,
17251725
@JsonProperty("_meta") Map<String, Object> meta,
1726-
@JsonProperty("ttlMs") Integer ttlMs,
1726+
@JsonProperty("ttlMs") Long ttlMs,
17271727
@JsonProperty("cacheScope") CacheScope cacheScope) implements Result { // @formatter:on
17281728

17291729
public ListResourceTemplatesResult {
@@ -1734,7 +1734,7 @@ public record ListResourceTemplatesResult( // @formatter:off
17341734
static ListResourceTemplatesResult fromJson(
17351735
@JsonProperty("resourceTemplates") List<ResourceTemplate> resourceTemplates,
17361736
@JsonProperty("nextCursor") String nextCursor, @JsonProperty("_meta") Map<String, Object> meta,
1737-
@JsonProperty("ttlMs") Integer ttlMs, @JsonProperty("cacheScope") CacheScope cacheScope) {
1737+
@JsonProperty("ttlMs") Long ttlMs, @JsonProperty("cacheScope") CacheScope cacheScope) {
17381738
if (resourceTemplates == null) {
17391739
logger.warn(
17401740
"ListResourceTemplatesResult: missing required field 'resourceTemplates' during deserialization, using default []");
@@ -1766,7 +1766,7 @@ public static class Builder {
17661766

17671767
private Map<String, Object> meta;
17681768

1769-
private Integer ttlMs;
1769+
private Long ttlMs;
17701770

17711771
private CacheScope cacheScope;
17721772

@@ -1785,7 +1785,7 @@ public Builder meta(Map<String, Object> meta) {
17851785
return this;
17861786
}
17871787

1788-
public Builder ttlMs(Integer ttlMs) {
1788+
public Builder ttlMs(Long ttlMs) {
17891789
this.ttlMs = ttlMs;
17901790
return this;
17911791
}
@@ -1876,7 +1876,7 @@ public ReadResourceRequest build() {
18761876
public record ReadResourceResult( // @formatter:off
18771877
@JsonProperty("contents") List<ResourceContents> contents,
18781878
@JsonProperty("_meta") Map<String, Object> meta,
1879-
@JsonProperty("ttlMs") Integer ttlMs,
1879+
@JsonProperty("ttlMs") Long ttlMs,
18801880
@JsonProperty("cacheScope") CacheScope cacheScope) implements Result { // @formatter:on
18811881

18821882
public ReadResourceResult {
@@ -1885,7 +1885,7 @@ public record ReadResourceResult( // @formatter:off
18851885

18861886
@JsonCreator
18871887
static ReadResourceResult fromJson(@JsonProperty("contents") List<ResourceContents> contents,
1888-
@JsonProperty("_meta") Map<String, Object> meta, @JsonProperty("ttlMs") Integer ttlMs,
1888+
@JsonProperty("_meta") Map<String, Object> meta, @JsonProperty("ttlMs") Long ttlMs,
18891889
@JsonProperty("cacheScope") CacheScope cacheScope) {
18901890
if (contents == null) {
18911891
logger.warn(
@@ -1915,7 +1915,7 @@ public static class Builder {
19151915

19161916
private Map<String, Object> meta;
19171917

1918-
private Integer ttlMs;
1918+
private Long ttlMs;
19191919

19201920
private CacheScope cacheScope;
19211921

@@ -1929,7 +1929,7 @@ public Builder meta(Map<String, Object> meta) {
19291929
return this;
19301930
}
19311931

1932-
public Builder ttlMs(Integer ttlMs) {
1932+
public Builder ttlMs(Long ttlMs) {
19331933
this.ttlMs = ttlMs;
19341934
return this;
19351935
}
@@ -2512,7 +2512,7 @@ public record ListPromptsResult( // @formatter:off
25122512
@JsonProperty("prompts") List<Prompt> prompts,
25132513
@JsonProperty("nextCursor") String nextCursor,
25142514
@JsonProperty("_meta") Map<String, Object> meta,
2515-
@JsonProperty("ttlMs") Integer ttlMs,
2515+
@JsonProperty("ttlMs") Long ttlMs,
25162516
@JsonProperty("cacheScope") CacheScope cacheScope) implements Result { // @formatter:on
25172517

25182518
public ListPromptsResult {
@@ -2522,7 +2522,7 @@ public record ListPromptsResult( // @formatter:off
25222522
@JsonCreator
25232523
static ListPromptsResult fromJson(@JsonProperty("prompts") List<Prompt> prompts,
25242524
@JsonProperty("nextCursor") String nextCursor, @JsonProperty("_meta") Map<String, Object> meta,
2525-
@JsonProperty("ttlMs") Integer ttlMs, @JsonProperty("cacheScope") CacheScope cacheScope) {
2525+
@JsonProperty("ttlMs") Long ttlMs, @JsonProperty("cacheScope") CacheScope cacheScope) {
25262526
if (prompts == null) {
25272527
logger.warn(
25282528
"ListPromptsResult: missing required field 'prompts' during deserialization, using default []");
@@ -2553,7 +2553,7 @@ public static class Builder {
25532553

25542554
private Map<String, Object> meta;
25552555

2556-
private Integer ttlMs;
2556+
private Long ttlMs;
25572557

25582558
private CacheScope cacheScope;
25592559

@@ -2572,7 +2572,7 @@ public Builder meta(Map<String, Object> meta) {
25722572
return this;
25732573
}
25742574

2575-
public Builder ttlMs(Integer ttlMs) {
2575+
public Builder ttlMs(Long ttlMs) {
25762576
this.ttlMs = ttlMs;
25772577
return this;
25782578
}
@@ -2746,7 +2746,7 @@ public record ListToolsResult( // @formatter:off
27462746
@JsonProperty("tools") List<Tool> tools,
27472747
@JsonProperty("nextCursor") String nextCursor,
27482748
@JsonProperty("_meta") Map<String, Object> meta,
2749-
@JsonProperty("ttlMs") Integer ttlMs,
2749+
@JsonProperty("ttlMs") Long ttlMs,
27502750
@JsonProperty("cacheScope") CacheScope cacheScope) implements Result { // @formatter:on
27512751

27522752
public ListToolsResult {
@@ -2756,7 +2756,7 @@ public record ListToolsResult( // @formatter:off
27562756
@JsonCreator
27572757
static ListToolsResult fromJson(@JsonProperty("tools") List<Tool> tools,
27582758
@JsonProperty("nextCursor") String nextCursor, @JsonProperty("_meta") Map<String, Object> meta,
2759-
@JsonProperty("ttlMs") Integer ttlMs, @JsonProperty("cacheScope") CacheScope cacheScope) {
2759+
@JsonProperty("ttlMs") Long ttlMs, @JsonProperty("cacheScope") CacheScope cacheScope) {
27602760
if (tools == null) {
27612761
logger.warn("ListToolsResult: missing required field 'tools' during deserialization, using default []");
27622762
tools = List.of();
@@ -2786,7 +2786,7 @@ public static class Builder {
27862786

27872787
private Map<String, Object> meta;
27882788

2789-
private Integer ttlMs;
2789+
private Long ttlMs;
27902790

27912791
private CacheScope cacheScope;
27922792

@@ -2805,7 +2805,7 @@ public Builder meta(Map<String, Object> meta) {
28052805
return this;
28062806
}
28072807

2808-
public Builder ttlMs(Integer ttlMs) {
2808+
public Builder ttlMs(Long ttlMs) {
28092809
this.ttlMs = ttlMs;
28102810
return this;
28112811
}

mcp-test/src/test/java/io/modelcontextprotocol/spec/McpSchemaTests.java

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3038,7 +3038,7 @@ void testListResourcesResultWithTtl() throws Exception {
30383038

30393039
McpSchema.ListResourcesResult result = McpSchema.ListResourcesResult.builder(List.of(resource))
30403040
.nextCursor("next")
3041-
.ttlMs(60000)
3041+
.ttlMs(60000L)
30423042
.cacheScope(McpSchema.CacheScope.PUBLIC)
30433043
.build();
30443044

@@ -3050,7 +3050,7 @@ void testListResourcesResultWithTtl() throws Exception {
30503050

30513051
McpSchema.ListResourcesResult deserialized = JSON_MAPPER.readValue(value,
30523052
McpSchema.ListResourcesResult.class);
3053-
assertThat(deserialized.ttlMs()).isEqualTo(60000);
3053+
assertThat(deserialized.ttlMs()).isEqualTo(60000L);
30543054
assertThat(deserialized.cacheScope()).isEqualTo(McpSchema.CacheScope.PUBLIC);
30553055
assertThat(deserialized.resources()).hasSize(1);
30563056
}
@@ -3080,7 +3080,7 @@ void testListResourceTemplatesResultWithTtl() throws Exception {
30803080

30813081
McpSchema.ListResourceTemplatesResult result = McpSchema.ListResourceTemplatesResult
30823082
.builder(List.of(template))
3083-
.ttlMs(30000)
3083+
.ttlMs(30000L)
30843084
.cacheScope(McpSchema.CacheScope.PRIVATE)
30853085
.build();
30863086

@@ -3089,7 +3089,7 @@ void testListResourceTemplatesResultWithTtl() throws Exception {
30893089

30903090
McpSchema.ListResourceTemplatesResult deserialized = JSON_MAPPER.readValue(value,
30913091
McpSchema.ListResourceTemplatesResult.class);
3092-
assertThat(deserialized.ttlMs()).isEqualTo(30000);
3092+
assertThat(deserialized.ttlMs()).isEqualTo(30000L);
30933093
assertThat(deserialized.cacheScope()).isEqualTo(McpSchema.CacheScope.PRIVATE);
30943094
}
30953095

@@ -3118,7 +3118,7 @@ void testReadResourceResultWithTtl() throws Exception {
31183118
.build();
31193119

31203120
McpSchema.ReadResourceResult result = McpSchema.ReadResourceResult.builder(List.of(contents))
3121-
.ttlMs(0)
3121+
.ttlMs(0L)
31223122
.cacheScope(McpSchema.CacheScope.PRIVATE)
31233123
.build();
31243124

@@ -3127,7 +3127,7 @@ void testReadResourceResultWithTtl() throws Exception {
31273127

31283128
McpSchema.ReadResourceResult deserialized = JSON_MAPPER.readValue(value,
31293129
McpSchema.ReadResourceResult.class);
3130-
assertThat(deserialized.ttlMs()).isEqualTo(0);
3130+
assertThat(deserialized.ttlMs()).isEqualTo(0L);
31313131
assertThat(deserialized.cacheScope()).isEqualTo(McpSchema.CacheScope.PRIVATE);
31323132
}
31333133

@@ -3155,7 +3155,7 @@ void testListPromptsResultWithTtl() throws Exception {
31553155
.build();
31563156

31573157
McpSchema.ListPromptsResult result = McpSchema.ListPromptsResult.builder(List.of(prompt))
3158-
.ttlMs(120000)
3158+
.ttlMs(120000L)
31593159
.cacheScope(McpSchema.CacheScope.PUBLIC)
31603160
.build();
31613161

@@ -3164,7 +3164,7 @@ void testListPromptsResultWithTtl() throws Exception {
31643164

31653165
McpSchema.ListPromptsResult deserialized = JSON_MAPPER.readValue(value,
31663166
McpSchema.ListPromptsResult.class);
3167-
assertThat(deserialized.ttlMs()).isEqualTo(120000);
3167+
assertThat(deserialized.ttlMs()).isEqualTo(120000L);
31683168
assertThat(deserialized.cacheScope()).isEqualTo(McpSchema.CacheScope.PUBLIC);
31693169
}
31703170

@@ -3194,7 +3194,7 @@ void testListToolsResultWithTtl() throws Exception {
31943194

31953195
McpSchema.ListToolsResult result = McpSchema.ListToolsResult.builder(List.of(tool))
31963196
.nextCursor("cursor")
3197-
.ttlMs(300000)
3197+
.ttlMs(300000L)
31983198
.cacheScope(McpSchema.CacheScope.PUBLIC)
31993199
.build();
32003200

@@ -3205,7 +3205,7 @@ void testListToolsResultWithTtl() throws Exception {
32053205
.containsEntry("nextCursor", "cursor");
32063206

32073207
McpSchema.ListToolsResult deserialized = JSON_MAPPER.readValue(value, McpSchema.ListToolsResult.class);
3208-
assertThat(deserialized.ttlMs()).isEqualTo(300000);
3208+
assertThat(deserialized.ttlMs()).isEqualTo(300000L);
32093209
assertThat(deserialized.cacheScope()).isEqualTo(McpSchema.CacheScope.PUBLIC);
32103210
assertThat(deserialized.tools()).hasSize(1);
32113211
assertThat(deserialized.nextCursor()).isEqualTo("cursor");
@@ -3247,7 +3247,7 @@ void testListResourcesResultToleratesUnknownFields() throws Exception {
32473247
McpSchema.ListResourcesResult result = JSON_MAPPER.readValue("""
32483248
{"resources":[],"ttlMs":5000,"cacheScope":"public","futureField":"ignored"}""",
32493249
McpSchema.ListResourcesResult.class);
3250-
assertThat(result.ttlMs()).isEqualTo(5000);
3250+
assertThat(result.ttlMs()).isEqualTo(5000L);
32513251
assertThat(result.cacheScope()).isEqualTo(McpSchema.CacheScope.PUBLIC);
32523252
}
32533253

@@ -3256,7 +3256,7 @@ void testListResourceTemplatesResultToleratesUnknownFields() throws Exception {
32563256
McpSchema.ListResourceTemplatesResult result = JSON_MAPPER.readValue("""
32573257
{"resourceTemplates":[],"ttlMs":5000,"cacheScope":"private","futureField":"ignored"}""",
32583258
McpSchema.ListResourceTemplatesResult.class);
3259-
assertThat(result.ttlMs()).isEqualTo(5000);
3259+
assertThat(result.ttlMs()).isEqualTo(5000L);
32603260
assertThat(result.cacheScope()).isEqualTo(McpSchema.CacheScope.PRIVATE);
32613261
}
32623262

@@ -3274,7 +3274,7 @@ void testListPromptsResultToleratesUnknownFields() throws Exception {
32743274
McpSchema.ListPromptsResult result = JSON_MAPPER.readValue("""
32753275
{"prompts":[],"ttlMs":10000,"cacheScope":"public","futureField":"ignored"}""",
32763276
McpSchema.ListPromptsResult.class);
3277-
assertThat(result.ttlMs()).isEqualTo(10000);
3277+
assertThat(result.ttlMs()).isEqualTo(10000L);
32783278
assertThat(result.cacheScope()).isEqualTo(McpSchema.CacheScope.PUBLIC);
32793279
}
32803280

@@ -3283,7 +3283,7 @@ void testListToolsResultToleratesUnknownFields() throws Exception {
32833283
McpSchema.ListToolsResult result = JSON_MAPPER.readValue("""
32843284
{"tools":[],"ttlMs":60000,"cacheScope":"public","futureField":"ignored"}""",
32853285
McpSchema.ListToolsResult.class);
3286-
assertThat(result.ttlMs()).isEqualTo(60000);
3286+
assertThat(result.ttlMs()).isEqualTo(60000L);
32873287
assertThat(result.cacheScope()).isEqualTo(McpSchema.CacheScope.PUBLIC);
32883288
}
32893289

0 commit comments

Comments
 (0)