Repository navigation
feat: upgrade to Spring Boot 4.1.1 and Spring AI 2.0.1 - #23
Conversation
|
Thanks for the update on this one... We will merge when we get an official Spring AI 2.0 release! |
* feat: implement observability with OpenTelemetry and Micrometer, add logging configuration, and enable tracing with annotation support * test(observability): implement distributed tracing tests for Spring Boot 3.5 Add comprehensive distributed tracing test suite using SimpleTracer from micrometer-tracing-test library. This is the Spring Boot 3-native approach for testing observability without requiring external infrastructure. Key changes: - Add DistributedTracingTest with 6 passing tests for @observed methods - Add OpenTelemetryTestConfiguration providing SimpleTracer as @primary bean - Add OtlpExportIntegrationTest (disabled due to Jetty dependency issue) - Add LgtmAssertions and TraceAssertions utility classes - Add micrometer-tracing-bridge-otel to bridge Observation API to OpenTelemetry - Add spring-boot-starter-aop for @observed annotation support - Add test dependencies: micrometer-tracing-test, awaitility, Jetty modules Test results: - DistributedTracingTest: 6/6 tests passing - Spans successfully captured from @observed annotations - Build: SUCCESS (219 tests passing, 0 failures) Spring Boot 3.5 uses Micrometer Observation → Micrometer Tracing → OpenTelemetry bridge, which differs from Spring Boot 4's direct OpenTelemetry integration. Adapted from PR #23 (Spring Boot 4 implementation) with modifications for Spring Boot 3.5 architecture and APIs. --------- Signed-off-by: adityamparikh <aditya.m.parikh@gmail.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
|
Looks like you have some conflicts.. I think you need to update from main to pick up the new ci stuff? |
6bc312d to
6427366
Compare
9bbfae5 to
857fa32
Compare
Migrate the Solr MCP server from Spring Boot 3.5.x / Spring AI 1.1.x to Spring Boot 4.1.0 and Spring AI 2.0.0 GA. Highlights: - Jackson 3: tools.jackson.databind replaces com.fasterxml.jackson.databind (annotations stay in com.fasterxml.jackson.annotation); the MCP SDK uses the mcp-json-jackson3 module. JacksonException replaces IOException/ JsonProcessingException; JsonNode.properties()/asString() replace fields()/asText(). - MCP annotations: package moved from org.springaicommunity.mcp.annotation to org.springframework.ai.mcp.annotation (now part of Spring AI core). - Modular starters: spring-boot-starter-web -> -webmvc + -json; explicit spring-ai-autoconfigure-mcp-server-common (no longer pulled transitively after Spring AI 2.0.0-M7); modular test starters (actuator / opentelemetry / webmvc). - Observability: spring-boot-starter-opentelemetry (SB4 idiomatic) for traces, metrics, and OTLP log export, replacing the manual OTel BOM + micrometer-tracing-bridge-otel approach; spring-boot-starter-aspectj for @observed; OpenTelemetry logback appender installed programmatically via InstallOpenTelemetryAppender; management.opentelemetry.* OTLP properties. - Testcontainers 2.x module/package renames. - JSpecify is built into Spring Boot 4, so the explicit dependency is dropped. - GraalVM native: AOT NullAway exclusions for generated sources, JUnit-platform build-time init, DefaultMetaProvider + Solr API model reflection hints, and per-profile AOT documentation; dependency-resolution alignment for opentelemetry-proto and opentelemetry-api-incubator against the Spring Boot 4.1.0 BOM. Both Spring Boot 4.1.0 and Spring AI 2.0.0 are GA on Maven Central, so no milestone repositories are required. Scope is limited to the Spring Boot 4 / Spring AI 2.0 upgrade and its required changes; unrelated CI, Solr-version-matrix, and Solr 10 metrics changes are intentionally excluded. Signed-off-by: adityamparikh <aditya.m.parikh@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… JSON test to Jackson 3 Resolving PR #23 (sb4 -> main) onto current main surfaced two build breaks that the conflict resolution had to fix: 1. SBOM completeness gate failed. `generateBinaryLicense` compares the CycloneDX SBOM against the shipped `productionRuntimeClasspath`, but `cyclonedxBom` was never configured for it. Spring Boot's `CycloneDxPluginAction` only auto-configures the cyclonedx plugin version it recognizes (3.x for Spring Boot 4.1.0); we stay pinned to 2.4.1 because cyclonedx 3.x fails at configuration time on Gradle 9.4.1 (variant-mutation conflict on `:cyclonedxDirectBom`). With 2.4.1 unrecognized, the task fell back to plugin defaults: it wrote `build/reports/bom.json` (not `application.cdx.json`) and scanned the wrong configuration set (stale Jackson 2, none of the Spring Boot 4 modular jars), so the gate reported ~30 bundled deps "absent from the SBOM". Configure the task explicitly: `outputName = "application.cdx"` and `includeConfigs = [productionRuntimeClasspath]`. 2. `JsonResponseParserContentTypesTest` (added on main via #90) imported the Jackson 2 `com.fasterxml.jackson.databind.ObjectMapper`, but SB4 migrated `JsonResponseParser` to Jackson 3. Use `tools.jackson.databind.json.JsonMapper` (the project's Jackson 3 mapper-construction pattern) instead. Update the AGENTS.md SBOM Architecture note to match the explicit wiring. `./gradlew build` is green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: adityamparikh <aditya.m.parikh@gmail.com>
The lgtm service published Grafana on "3000:3000" (all interfaces) while setting GF_AUTH_ANONYMOUS_ORG_ROLE=Admin, so any host that could reach the developer's machine had unauthenticated admin access to the observability stack - no credentials, no prompt. Verified against the running container: - Old config: anonymous POST /api/folders -> HTTP 200, folder created. - New config: same request -> HTTP 403 "folders:create" denied. - Grafana answers on 127.0.0.1:3000 but the LAN address refuses the connection. Defaults are now loopback-only and read-only. Both are overridable for the cases that genuinely need them, so the previous behaviour stays available but has to be asked for: GF_ANON_ROLE=Admin docker compose up -d lgtm # editable dashboards GRAFANA_BIND=0.0.0.0 docker compose up -d lgtm # expose on a trusted LAN The OTLP receivers (4317/4318) are bound the same way via OTLP_BIND. The application posts telemetry to http://localhost:4318 by default, so the documented workflow is unaffected. Reported by a CodeRabbit review of #23. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Aditya Parikh <aditya.m.parikh@gmail.com>
The lgtm service tracked grafana/otel-lgtm:latest, so a rebuild could pull a
different observability stack without any change to this repo. Pin 0.30.0
(current release as of 2026-07-31).
Verified against the pinned image rather than assumed:
- Provisioned Grafana datasources are Loki, Prometheus (default), Pyroscope
and Tempo. There is no Mimir datasource, and the image ships a prometheus
binary and prometheus.yaml with no mimir equivalent.
- OTLP ingestion works end to end on this tag: POST /v1/metrics returned 200
and Prometheus then answered probe_counter_total{service_name=
"solr-mcp-probe"} = 7.
So the docs were sending readers to a datasource that does not exist -
"Select Mimir as the datasource" could not be followed. Corrected across
compose.yaml and dev-docs/Observability.md, and added Pyroscope, which the
stack provides but the docs never mentioned. The architecture diagram was
redrawn (Prometheus is wider than Mimir) and all rows re-aligned to 81
columns.
The LGTM table keeps its "M is for Mimir" row - that is what the acronym
stands for - but now says the image actually ships Prometheus.
Reported by a CodeRabbit review of #23.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Aditya Parikh <aditya.m.parikh@gmail.com>
Rebasing the Spring Boot 4 / Spring AI 2.0 branch onto current main applied cleanly at the textual level but left three test-side breaks that only compiling and running the suite surfaces. 1. `SearchServiceIntegrationTest` and `IndexingServiceIntegrationTest` failed to compile. Main still uses the wildcard `import static org.junit.jupiter.api.Assertions.*`, which this branch had expanded to explicit imports. Git merged the explicit list, so the assertions main added since the fork point (apache#166 `assertThrows`, apache#165 `assertFalse`) had no import. Add the two missing static imports rather than reintroducing the wildcard. 2. `SolrNativeHintsTest.registersDefaultMetaProviderConstructorHint` (added on main via apache#172) asserts a hint for `org.springaicommunity.mcp.context.DefaultMetaProvider`. Spring AI 2.x relocated that class to `org.springframework.ai.mcp.annotation.context.DefaultMetaProvider`, which the Registrar already registers. Because `registerTypeIfPresent` silently no-ops for a class that is absent from the classpath, the legacy coordinate registers nothing here and the assertion failed. Point the test at the coordinate that Spring AI 2.x actually ships; the legacy registration stays in the Registrar defensively. `./gradlew build` is green on JDK 25: 372 tests, 0 failures, 0 errors, 7 skipped. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Aditya Parikh <aditya.m.parikh@gmail.com>
…line
0.0.6 is built against the Spring Boot 3 line: its POM declares
spring-core 6.2.9 and spring-security-{web,config,core,oauth2-*} 6.5.2,
and it predates mcp-core 2.x entirely. This branch ships Spring Framework
7.0.8 and Spring Security 7.1.0 via the Spring Boot 4.1.0 BOM, so the
0.0.6 bytecode was running against a Security major it never saw.
0.1.14 is the current release of the same library on the Boot 4 line:
spring-core 7.0.8, spring-security-* 7.1.0, mcp-core 2.0.0 — matching
exactly what Spring Boot 4.1.0 and Spring AI 2.0.0 put on the classpath.
The upgrade is a version-catalog change only; McpServerOAuth2Configurer's
API in HttpSecurityConfiguration is unchanged.
Note on verification: no automated test in this repo exercises
McpServerOAuth2Configurer on any version. It is wired only when
OAUTH2_ISSUER_URI is set (HttpSecurityConfiguration#secured), and
DockerImageHttpIntegrationTest deliberately runs without an issuer since
it has no IdP. That coverage gap is pre-existing and worth closing
separately.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Aditya Parikh <aditya.m.parikh@gmail.com>
…y main merges The upstream/main merges brought main's DEVELOPMENT.md wording into sb4 unchanged, so the sb4 guide described Spring Boot 3.5's observability stack, kebab-case span names, and an OtlpExportIntegrationTest that main re-enabled in apache#198 as still disabled. It now describes what sb4 runs: Micrometer Observation bridged by spring-boot-starter-opentelemetry, ClassName#methodName span names, and the enabled LGTM export test. The OTel BOM bullet referred to a BOM sb4 no longer imports; it now points at the dependency-alignment notes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014AYFY1qefKnAxMshu5pYjg
feat: add support for STDIO and SSE transport modes in Solr MCP server
…e#41) * feat: implement observability with OpenTelemetry and Micrometer, add logging configuration, and enable tracing with annotation support * test(observability): implement distributed tracing tests for Spring Boot 3.5 Add comprehensive distributed tracing test suite using SimpleTracer from micrometer-tracing-test library. This is the Spring Boot 3-native approach for testing observability without requiring external infrastructure. Key changes: - Add DistributedTracingTest with 6 passing tests for @observed methods - Add OpenTelemetryTestConfiguration providing SimpleTracer as @primary bean - Add OtlpExportIntegrationTest (disabled due to Jetty dependency issue) - Add LgtmAssertions and TraceAssertions utility classes - Add micrometer-tracing-bridge-otel to bridge Observation API to OpenTelemetry - Add spring-boot-starter-aop for @observed annotation support - Add test dependencies: micrometer-tracing-test, awaitility, Jetty modules Test results: - DistributedTracingTest: 6/6 tests passing - Spans successfully captured from @observed annotations - Build: SUCCESS (219 tests passing, 0 failures) Spring Boot 3.5 uses Micrometer Observation → Micrometer Tracing → OpenTelemetry bridge, which differs from Spring Boot 4's direct OpenTelemetry integration. Adapted from PR apache#23 (Spring Boot 4 implementation) with modifications for Spring Boot 3.5 architecture and APIs. --------- Signed-off-by: adityamparikh <aditya.m.parikh@gmail.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Spring Boot 4.1.1, Spring AI 2.0.1, mcp-server-security 0.1.14 and the
MCP Java SDK 2.0.1 are already the latest GA releases; this moves the
rest of the catalog up.
- OTel logback appender 2.21.0-alpha -> 2.28.1-alpha, the newest release
built against the opentelemetry-api 1.62.0 that Boot 4.1.1 manages. It
pulls opentelemetry-api-incubator 1.62.0-alpha itself, so the
resolutionStrategy rule forcing that version is removed.
- Testcontainers 2.0.2 -> 2.0.5, commonmark 0.28.0 -> 0.30.0,
Error Prone 2.48.0 -> 2.50.0, NullAway 0.13.1 -> 0.14.2.
- GraalVM native plugin 0.10.6 -> 1.1.14. Since 0.11 its JUnit feature
handles build-time initialization of the test plan; the manual
org.junit.platform.* --initialize-at-build-time entries now put a JUnit
logger in the image heap and fail nativeTestCompile, so they are dropped.
- Spotless 7.0.2 -> 8.9.0 with Eclipse JDT pinned to 4.34 and ktlint to
1.5.0 (the 7.0.2 defaults): JDT 4.39 collapses Javadoc <pre>{@code}
blocks and folds @param/@see tags into the preceding paragraph.
- Jib 3.5.3 -> 3.5.4, Error Prone plugin 5.1.0 -> 5.1.1, Apache RAT
plugin 0.8.2 -> 0.11.0, buildSrc JUnit 5.12.2 -> 6.1.3, Gradle 9.7.1 -> 9.8.0.
Verified: ./gradlew build (422 tests, 0 failed, 0 skipped) and
./gradlew nativeTest -Pnative (281 passed, 0 failed, 138 skipped).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Aditya Parikh <aditya.m.parikh@gmail.com>
|
This is the big one before we go to 1.0... we don't want to release on onld spring stuff... |
Brings in apache#195 apache#200 apache#207 apache#212 apache#214 apache#215 apache#221 apache#230 apache#231 apache#233 apache#234 apache#235 apache#238 apache#239 apache#242 apache#243 apache#244 apache#247 and apache#191 apache#192, keeping the Spring Boot 4.1 / Spring AI 2.0 / Jackson 3 / Boot OTel starter line. Resolutions beyond the textual conflicts: - libs.versions.toml: keep sb4's plugin versions, add main's changelog-plugin. - build.gradle.kts (nativeTest args): keep sb4's removal of the manual org.junit.platform.* build-time init (GraalVM plugin >= 0.11 does it), take main's -H:IncludeResources=shows-markdown\.md. - buildSrc: cyclonedx-core-java 10.2.1 -> 13.1.0, the version the cyclonedx 3.4.1 plugin uses. apache#247 pinned it to match plugin 2.4.1; the older model on buildSrc's classpath shadowed the plugin's and failed cyclonedxDirectBom (no Version.VERSION_17). - AliasService (apache#214): MCP annotations from org.springframework.ai.mcp. - ShowsSampleDataTest (apache#207): Jackson 3 JsonMapper. - Tests from apache#195/apache#207/apache#212: add the explicit Assertions static imports sb4 uses in place of main's wildcard. - docs/observability.md: rewrite apache#230's Boot 3 text (gRPC 4317, one shared endpoint, OTel-semconv metric names, /actuator/prometheus, kebab-case span names) for OTLP/HTTP per-signal URLs, Micrometer metrics in milliseconds and ClassName#method spans. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Aditya Parikh <aditya.m.parikh@gmail.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Aditya Parikh <aditya.m.parikh@gmail.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Aditya Parikh <aditya.m.parikh@gmail.com>
…enerated file gradle-wrapper.properties is generated, and apache#188 set retries=3 by hand in it. Regenerating the wrapper for 9.8.0 wrote the generator's default back (retries=0), silently dropping that setting. Gradle 9.8's Wrapper task exposes `retries`, so set it there, with distributionType BIN, and regenerate with `./gradlew wrapper --gradle-version latest`. 9.8.0 is the current release; future upgrades keep retries=3 without a hand edit. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Aditya Parikh <aditya.m.parikh@gmail.com>
spring-ai-autoconfigure-mcp-server-common was declared because Spring AI 2.0.0-M7 made it optional in the webmvc starter. In 2.0.1, spring-ai-autoconfigure-mcp-server-webmvc depends on it at compile scope again, so it arrives transitively. spring-ai-starter-mcp-client and spring-ai-autoconfigure-mcp-client-common were on the test classpath, but the tests build their clients from the MCP Java SDK directly (io.modelcontextprotocol.client.McpClient with the stdio and streamable-HTTP transports in mcp-core). Nothing uses a Spring AI client class or a spring.ai.mcp.client.* property. The SBOM is unchanged (same 140 components). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Aditya Parikh <aditya.m.parikh@gmail.com>
…tion value The comment said io.modelcontextprotocol >= 0.16. The check arrived in SDK 2.0.0: CompleteArgument in 0.18.x and 1.0-1.1.x accepts a null value, and main (on 0.18) still exercises that path. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Aditya Parikh <aditya.m.parikh@gmail.com>
- AGENTS.md: version is 1.0.0-SNAPSHOT; the native OTel build-time init is for the logback appender (there is no instrumentation BOM any more); list the native hints SolrNativeHints actually registers; JSpecify arrives through spring-core; SBOM path build/reports/cyclonedx/; drop the stale component count; document the wrapper upgrade command. - dev-docs/Observability.md: lgtm is boot-ignored, so bootRun never starts it; service name is solr-mcp; LogQL filters on the level and trace_id attributes (|= "ERROR" and | json match nothing); PromQL uses the OTLP registry's _milliseconds_ timers and job label; pin the lgtm image tag in the example. - docs/site observability page: regenerated from docs/observability.md; it still described the Boot 3 gRPC/4317 export and /actuator/prometheus. - docs/observability.md, DEVELOPMENT.md: the lgtm image runs Prometheus, not Mimir; SBOM path; OTel native note. - observability test README: service, metric and span names, and the Boot 4 export properties. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Aditya Parikh <aditya.m.parikh@gmail.com>
The resolution rule forced opentelemetry-proto to 1.3.2-alpha, built against protobuf 3.x, citing a NoSuchMethodError seen with 1.8.0-alpha on the Boot 3 line. On Boot 4.1.1 the only consumer, micrometer-registry-otlp 1.17.1, is built against 1.10.0-alpha, and Boot manages protobuf-java 4.35.1, so the rule downgraded the proto classes below the protobuf runtime they run on. Without the rule the graph resolves opentelemetry-proto 1.10.0-alpha with protobuf-java 4.35.1, the pair Micrometer is built with. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Aditya Parikh <aditya.m.parikh@gmail.com>
spring-ai-spring-boot-docker-compose 2.0.1 declares its vector-store starters, spring-boot-starter-mongodb included, as optional, so none of them reach developmentOnly and the exclusion matched nothing. Without it the two docker-compose modules go back to the spring-boot-dev bundle, as on main; developmentOnly still resolves no Mongo artifact. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Aditya Parikh <aditya.m.parikh@gmail.com>
compose.yaml pinned grafana/otel-lgtm 0.30.0 while the version catalog pins the Testcontainers image to 0.33.0 (test-image-lgtm), so local bootRun and OtlpExportIntegrationTest ran different collector and backend versions. Use 0.33.0 in both. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Aditya Parikh <aditya.m.parikh@gmail.com>
…tibility runs The solr-compatibility matrix only runs on pushes to main, and has failed there on every push: Solr 10 removed /admin/mbeans, so cache and handler stats degrade to null as documented, but three CollectionService integration tests required them non-null; Solr 8.11 predates DenseVectorField, so the dense-vector schema round trip is rejected. TestcontainersConfiguration now exposes the image under test and its major version, and those tests assert what each version actually does (null stats on 10+, a RemoteSolrException below 9) instead of skipping. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Aditya Parikh <aditya.m.parikh@gmail.com>
The solr-compatibility job was gated on a "solr-compatibility" label that does not exist in the repository, and ci.yml does not trigger on labeled events, so the job was skipped on every PR. Version-specific failures (Solr 8.11, 9.4, 9.10, 10) therefore surfaced only on the next push to main via build-and-publish.yml. Drop the gate so PRs run the matrix. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Aditya Parikh <aditya.m.parikh@gmail.com>
With needs: integration-tests, any unit or integration failure made GitHub skip the whole matrix, so the PR showed a skipped compatibility check and no signal about other Solr versions. Depend on build like the unit-tests and integration-tests jobs, so the matrix always runs and reports its own result. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Aditya Parikh <aditya.m.parikh@gmail.com>
|
@epugh could you approve the workflow runs for 36f5c56? CI and Native Image are both waiting as
This push brings the Solr compatibility fix from #237 onto this branch. The matrix was gated on a |
… build The coc2026 image, native images and JAR are now built from the Spring Boot 4.1 / Spring AI 2.0 line (apache#23), which carries everything on main, so the card describes what that build does: - Fifteen tools, with the three alias tools in the toolbox table. - Step 3: CSV, XML and Markdown samples come from main's src/test/resources. CSV and XML go to Solr's own handlers, which report the payload accepted instead of a count. XML is Solr update XML, so its field names match JSON and the show_ prefix notes go; the Option B XML paste is converted to <add><doc> form. Markdown is one multi-record file and one tool call; its description is in content, which the step 6 note now says. - Step 4: one outcome, an empty facet (apache#175 is in the image). - Native Docker images are prebuilt for amd64 and arm64. - Observability: OTLP/HTTP on 4318 with a URL per signal, ClassName#method span names, timers in milliseconds, JVM metrics over OTLP rather than /actuator/prometheus. - Security: protected resource metadata for /mcp is served at the RFC 9728 path-suffixed URL. - Sizes (52 MB JAR, ~170 MB image) and the verified-against footer. - Table cards: fifteen tools, and ChatGPT in the client list. Every step was replayed against the published image for all four formats, including the Option B pastes, the observability panel against grafana/otel-lgtm 0.33.0, and the security panel against Keycloak. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Aditya Parikh <aditya.m.parikh@gmail.com>
Upgrades the server to Spring Boot 4.1.1 and Spring AI 2.0.1, with Jackson 3, the MCP Java SDK 2.0.1,
mcp-server-security0.1.14 and Spring Boot's own OpenTelemetry starter. All are GA on Maven Central; no milestone repositories are needed.Breaking changes (HTTP profile only)
OTEL_TRACES_URLchanges meaning: it was a base endpoint shared by all three signals (http://collector:4317) and is now the full traces URL (http://collector:4318/v1/traces). A value carried over unchanged does not error; traces simply stop arriving.OTEL_METRICS_URLandOTEL_LOGS_URLare new./actuator/prometheusis removed. Metrics leave over OTLP only, and now include the full Micrometer set (JVM, Tomcat, Spring Security, per-tool timers). Timers are exported in milliseconds (http_server_requests_milliseconds_*,method_observed_milliseconds_*).@Observedspan names change fromsearch-service#searchtoSearchService#search.See docs/observability.md.
Versions
mainmcp-bomimported ahead ofspring-ai-bom(Spring AI 2.0.1 resolves 2.0.0; 2.0.1 fixes stateless-server error handling, which is our HTTP profile, and bounds reads on the HTTP and STDIO transports)mcp-server-securityMcpServerOAuth2ConfigurerAPI unchangedopentelemetry-spring-boot-starterspring-boot-starter-opentelemetry(SDK managed by Boot) +opentelemetry-logback-appender-1.02.28.1-alphaspring-core)testcontainers-junit-jupiter,-solr,-grafana)cyclonedx-core-java10.2.1 → 13.1.0 to match itretries = 3now set on thewrappertask inbuild.gradle.kts, so regenerating the wrapper keeps it)Code changes
Jackson 3.
tools.jackson.databindreplacescom.fasterxml.jackson.databindinSolrConfig,JsonResponseParser,JsonDocumentCreator,JsonUtils,CollectionServiceandSchemaService.JacksonExceptionreplacesIOException/JsonProcessingExceptionin catch clauses;JsonNode.properties()/asString()replacefields()/asText(). Annotations stay incom.fasterxml.jackson.annotation. Test MCP clients build their transports withio.modelcontextprotocol.json.jackson3.JacksonMcpJsonMapper.MCP annotations.
org.springaicommunity.mcp.annotation→org.springframework.ai.mcp.annotation(now part of Spring AI) in all five service classes, includingAliasService. MCP SDK 2.0'sCompleteArgumentrejects a null value at construction, soCollectionServiceTest's null-completion case now asserts that instead of calling the service.Modular starters.
spring-boot-starter-web→-webmvc+-json;-aop→-aspectj(what@Observedneeds on Boot 4); modular test starters (-webmvc-test,-actuator-test,-opentelemetry-test). The test classpath no longer carriesspring-ai-starter-mcp-client: the tests build their clients from the MCP Java SDK directly.Observability.
spring-boot-starter-opentelemetryprovides traces, metrics and OTLP log export;micrometer-registry-otlpreplaces the Prometheus registry. The OTel logback appender is installed by a newInstallOpenTelemetryAppenderbean (@Profile("http")), since Boot 4 does not bundle it.application-http.propertiesusesmanagement.opentelemetry.*/management.otlp.*endpoints.opentelemetry-protoresolves to1.10.0-alpha, the versionmicrometer-registry-otlp1.17.1 is built against, alongside Boot's protobuf-java 4.35.1, with no version override.DistributedTracingTestis updated for the new span names and themanagement.tracing.export.otlp.enabledproperty.Profiles and logging.
application-stdio.propertiesexcludes the Boot 4.1 security auto-configuration classes (org.springframework.boot.security.autoconfigure.SecurityAutoConfigurationand...actuate.web.servlet.ManagementWebSecurityAutoConfiguration); the Boot 3 names would be silently ignored. It also stops settinglogging.pattern.console=: Boot copies that value into the JVM-wideCONSOLE_LOG_PATTERNsystem property and logback rejects an empty pattern, and since Framework 7 pauses a test's context on context switch, a stdio-profile test running first broke every later http-profile context in the same JVM. STDIO stays silent becauselogback-spring.xmldeclares no appenders for it.LoggingConfigurationTestguards against the empty pattern returning.GraalVM native.
MemberCategory.DECLARED_FIELDS(marked for removal) →ACCESS_DECLARED_FIELDS. New hints for the SolrJ 10 API model types (SolrJerseyResponse,ErrorInfo,CoreStatusResponseand nested types), the relocatedorg.springframework.ai.mcp.annotation.context.DefaultMetaProvider, and Solr'sEnvToSyspropMappings.properties/DeprecatedSystemPropertyMappings.propertiesresources. Error Prone / NullAway are disabled for the generatedcompileAotJava/compileAotTestJavasources. The manualorg.junit.platform.*--initialize-at-build-timeentries for the test binary are dropped; GraalVM native plugin 0.11+ handles that itself, and keeping them failsnativeTestCompile.SBOM. cyclonedx 3.x splits the work into
cyclonedxDirectBom(resolves dependencies, ownsincludeConfigs) andcyclonedxBom(aggregates). Boot 4.1'sCyclonedxPluginActionconfigures the output for 3.x and embeds it in the bootJar, so the manual output wiring is gone; the direct task is scoped toproductionRuntimeClasspath, because at defaults it adds ~100 test-only components that scanners would read as shipped. The license-notice plugin reads the SBOM frombuild/reports/cyclonedx/application.cdx.json. Resolves #186.compose.yaml.
grafana/otel-lgtmpinned to0.33.0instead oflatest, the same version the Testcontainers tests use; Grafana and the OTLP receivers bind to loopback by default (GRAFANA_BIND/OTLP_BINDto override), and anonymous access is Viewer rather than Admin (GF_ANON_ROLE=Adminto opt in).Docs.
AGENTS.md,README.md,docs/observability.md(per-signal endpoints, Micrometer metric names in milliseconds, upgrade callout), newdev-docs/Observability.md,dev-docs/DEVELOPMENT.md,dev-docs/graalvm-native-image.md(OTel version alignment),docs/security/stdio.md,docs/security/keycloak.md.Verification
./gradlew build(Java 25)./gradlew nativeTest -Pnative(GraalVM CE 25.0.2)@DisabledInNativeImage)LicenseNoticeTasksTest)./gradlew rat spotlessCheckgrafana/otel-lgtm)/mcprequest count matches the calls made./gradlew dockerIntegrationTestThe bootJar contains
META-INF/sbom/application.cdx.json,META-INF/LICENSEandMETA-INF/NOTICE. No automated test configures an OAuth2 issuer, soMcpServerOAuth2Configurerfrom the upgradedmcp-server-securityis not exercised by the suite.References
🤖 Generated with Claude Code