Propagate @McpResource(annotations = ...) to MCP wire objects - #6801
Open
a-yeyang wants to merge 1 commit into
Open
Propagate @McpResource(annotations = ...) to MCP wire objects#6801a-yeyang wants to merge 1 commit into
@McpResource(annotations = ...) to MCP wire objects#6801a-yeyang wants to merge 1 commit into
Conversation
Java annotation elements can never be `null`, so the compiler always materialises the declared default of `McpResource#annotations()`. Combined with the fact that none of the four Async/Sync[Stateless] McpResourceProvider classes read that value when building the `McpSchema.Resource` / `McpSchema.ResourceTemplate` objects they hand to the SDK, user-supplied `audience` / `priority` / `lastModified` values never reach the client. `ResourceAdapter` did look at the value but was gated on a non-empty `lastModified`, dropped the `lastModified` string itself, and never fired for URI templates — and, more importantly, was not used by the providers. Add a shared `ResourceAnnotationsUtils.toSchemaAnnotations` helper that uses `Method#getDefaultValue()` to obtain the declared default of `McpResource#annotations()` and returns `null` when the runtime value equals it (annotations use structural equality), otherwise copies `audience`, `priority` and `lastModified` verbatim into an `McpSchema.Annotations`. Call the helper from all four resource providers, for both direct-resource and URI-template paths, and fix `ResourceAdapter` to use the same helper. Add regression coverage in the four provider test classes for (a) the default-value case is not propagated, (b) explicit annotations reach direct resources, (c) explicit annotations reach resource templates, and (d) an audience-only change propagates without requiring `lastModified` to be set. Closes spring-projectsgh-6749 Signed-off-by: chenshiyang <88581400+a-yeyang@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #6749.
Problem
@McpResourcedeclares a nestedannotations = @McpAnnotations(audience, priority, lastModified)element. Because Java annotation elements can never benull, the compiler always materialises the declared default, so the mere presence of@McpResourceon a method makesannotations()return a non-null value regardless of whether the user actually set one.None of the four resource providers observed today take that value into account:
SyncMcpResourceProviderAsyncMcpResourceProviderSyncStatelessMcpResourceProviderAsyncStatelessMcpResourceProviderEach of them builds
McpSchema.Resource/McpSchema.ResourceTemplatedirectly and never callsResource.Builder#annotations(...)/ResourceTemplate.Builder#annotations(...), so user-suppliedaudience/priority/lastModifiedvalues never reach the MCP client.ResourceAdapter(the sibling helper) did look atannotations(), but it was gated on!lastModified.isEmpty(), silently dropped thelastModifiedvalue even when it fired, and did not handle the template path. It is also not used by the providers today, so its behaviour did not offset the provider-side omission.Change
mcp-annotations/common/ResourceAnnotationsUtils.toSchemaAnnotations(McpAnnotations):McpResource#annotations()at class-load time viaMethod#getDefaultValue()— no default constants have to be duplicated;nullwhen the runtime value structurally equals that default (annotations implement structuralequals), so the compiler-materialised default is not published to clients;audience,priorityandlastModifiedverbatim into anMcpSchema.Annotations.Resource.Builder#annotations(...)/ResourceTemplate.Builder#annotations(...).ResourceAdapter#asResourceand#asResourceTemplateto use the same helper.annotations()is not propagated;McpSchema.Resource;McpSchema.ResourceTemplate;lastModified).Scope kept intentionally narrow
lastModifiedcannot be dynamically computed per request; that is an API-shape change worth its own discussion and is not attempted here.ResourceAdapter; this PR does not touch title so the two changes stay orthogonal.Local validation
mvn -pl mcp/mcp-annotations test→ 1389 tests run, 0 failures, 0 errors, 2 skipped, including the new regression cases.mvn -pl mcp/mcp-annotations -DskipTests install(checkstyle +disable.checksprofile) → BUILD SUCCESS.mvn -pl mcp/mcp-annotations spring-javaformat:validate -DskipTests→ BUILD SUCCESS.DCO
Signed-off-by.