0.80.0 (2026-10-08)
ACP Java SDK 0.80.0 is a big feature release on the road to 1.0. It implements the latest Agent Client Protocol specification, and a cross-SDK compatibility suite verifies it against the TypeScript, Rust, Python and Kotlin SDKs over every transport each one supports. Agents are no longer limited to subprocesses: they can now serve many clients over Streamable HTTP and WebSocket. The@AcpAgent annotation programming model now works the same way in Spring Boot, Quarkus and
Micronaut, and in plain Java with no framework at all. Handlers run on your framework’s executor, or
on virtual threads. We put a great deal of effort into bug fixing, testing and reshaping the API to be
as developer-friendly as possible. There are breaking changes, so if you’re upgrading from 0.18, start
with the migration guide.
See Cross-SDK Compatibility for exactly what’s tested, what isn’t
yet, and how the feature set compares.
One protocol core, mounted natively into your framework. All of ACP’s protocol rules live in a
single framework-neutral core; each framework integration is a thin host that serves ACP on the
framework’s own server, port, TLS, security, metrics and threads. Spring Boot (MVC and WebFlux) and
Quarkus do this today, one server for the whole application; Micronaut native hosting is next, after
keeping ACP on a separate port in 0.80.0. See
Deployment topologies for exactly where ACP
listens in each case.
ACP over HTTP needs almost nothing from a web framework: one path, three HTTP methods, a JSON body in,
three kinds of reply out (JSON, empty, or an SSE stream), and WebSocket text frames. That’s why each
framework host is small and behaves the same; see
the full comparison.
Native integration, not a bolt-on. On Spring Boot (MVC and WebFlux) and Quarkus, ACP runs inside your
application: one server, one port for HTTP, SSE and WebSocket together, one TLS setup, one lifecycle
that starts and stops with your app, one place for metrics and logs, and your framework’s own threads.
And if you expose the agent remotely, your framework’s own security applies too, WebSocket handshake
included. See Spring Boot and
Quarkus for a concrete example.
Here’s the shape of it: @AcpAgent, @Prompt, @NewSession, and the rest carry the handlers;
whatever serves the class discovers them the same way. Plain Java needs nothing but acp-core and
acp-agent-support:
acp-spring-boot-starter/acp-spring-boot-autoconfigure moved from org.springaicommunity into
com.agentclientprotocol, versioned with the rest of the SDK (see the
migration guide for the
exact coordinate and package change); Quarkus and Micronaut support are new in 0.80.0. All three are
required (non-preview) modules.
Streamable HTTP and WebSocket are both served on the same /acp endpoint, not two separate ones.
As for where those handlers actually run: Micronaut’s virtual threads
on JDK 21+, Quarkus’s own worker pool, or an executor you choose yourself on Spring Boot and plain
Java. See each framework’s own “Where handlers run” section for specifics.
Forty-plus tutorial modules and a new set of concept pages are the fastest way to learn the
annotation model, cancellation, extension methods, elicitation, and the rest hands-on; see
Tutorials below.
Proof, not just claims: nearly 1,400 tests, load-testing scenarios that drive hundreds of
concurrent clients, and quality gates that fail the build on any violation, never baseline one away.
See Quality below.
Start with the quickstart or the
tutorial. Upgrading from 0.18.0? Read the
migration guide first; it has the full breaking-change list and a
checklist to work through. Curious about the wider protocol, the other language SDKs, or who else
implements ACP? See ACP Resources.
Features
- Session config options replace
session/set_model: an agent declares its own selectors (model choice is now just the one withcategory: "model"), plus a new boolean kind for simple on/off settings. - Cancellation and
$/cancel_request, in both directions, lets either side cancel a single in-flight request without ending the whole session; a prompt turn cancelled bysession/cancelnow always ends in stop reasoncancelled, whatever the handler does. - Extension methods (
_-prefixed custom requests and notifications) are a first-class, typed feature on every client and agent builder, not just a raw escape hatch. - Elicitation is stable, with explicit mode-checking: an agent can only ask for what the client actually advertised.
- Terminal authentication and logout: an agent can ask the client to run an interactive login, and advertise that it supports logging out.
- Streamable HTTP and WebSocket: a graceful shutdown window and
clearer connection/session routing, on top of the remote-agent support described above. A WebSocket
session gets its own idle timeout (30 minutes by default) and
initializedeadline (30 seconds), the same on every host and configurable from your framework, so a quiet session isn’t cut off by ordinary HTTP keep-alive tuning and an abandoned connection doesn’t leak. - Forward compatibility and
_meta: former enums (StopReason,ToolCallStatus, and others) are open value types, several unions gained explicitUnknown*fallback variants, and every schema record carries_meta. - Session list, close, resume and delete: the full session lifecycle from both sides, beyond the original create-and-prompt loop.
@UnstableAcpApi. Today that’s session fork and the providers methods; everything
listed above is a stable promise.
Tutorials
Ten new or extended modules, in the tutorial’s own order:- 31: Elicitation (extended)
- 33: Session Config Options
- 34: Extension Methods
- 35: Cancellation and Timeouts
- 36: Terminal Auth and Logout
- 37: Streamable HTTP and WebSocket
- 38: Spring Boot over HTTP
- 39: Forward Compatibility and _meta
- 40: Micronaut
- 41: Quarkus
Quality
-
Cross-SDK interop, over stdio, Streamable HTTP, and WebSocket:
See Cross-SDK Compatibility for what each cell means and how this SDK’s feature set compares: it’s among the most complete ACP SDKs, by that comparison.
- Safe by default: local listeners bind to localhost, browser origins are checked, and logs at INFO and above carry no message content. See Transports for how to expose an agent deliberately and what each log level can carry.
- Load testing. Scenarios drive hundreds of concurrent clients, on their own connections and sharing one HTTP/2 connection, each running real prompt turns with streaming updates.
- Nearly 1,400 tests, model-checked concurrency, and mutation testing on the protocol core (below).
-
Quality gates, every one enforced in
./mvnw verifyand never baselined:See the SDK’s own README for the current badges and exact coverage numbers; they change between releases and are not repeated here.
Requirements
- Java 17+
- Spring Boot 4.1 (for
acp-spring-boot-starter) - Quarkus 3.40 (for
acp-quarkus) - Micronaut 4 (for
acp-micronaut)
0.18.0 (2026-09-25)
Remote agents: the Streamable HTTP and WebSocket transport from the ACP RFD, over plainhttp:// and https://, and a choice of Jackson 2 or Jackson 3. See Remote agents for the code.
Added
- Streamable HTTP transport (RFD streamable-http-websocket-transport), contributed by @kamikaz1k (#7).
StreamableHttpAcpClientTransportinacp-coretalks to a remote agent over HTTP POST with SSE response streams. The newacp-streamable-http-jettymodule providesStreamableHttpAcpAgentTransport, a Jetty listener that serves HTTP/SSE and a WebSocket upgrade on the same path and hosts one agent per remote connection throughAcpAgentFactory. Header names and path match the TypeScript and Rust SDKs StreamableHttpAcpServletis public and mountable in any Servlet 6 container (Spring Boot, Tomcat, Jetty, Undertow) at your own path; register it with async support. It serves the HTTP/SSE profile; the WebSocket upgrade needsStreamableHttpAcpAgentTransport- Limits and keep-alive for the HTTP agent transport (
StreamableHttpAcpAgentTransportOptions): POST bodies capped at 16 MiB by default, bounded WebSocket send queues and provisionalsession/loadstreams, a: keep-alivecomment every 15 s on attached SSE streams, and 1,024 concurrent HTTP/2 streams per connection instead of Jetty’s default 128 - HTTP/2 over plain
http://: the client sends a bodiless GET first so that, against a server that speaks h2c, every request runs on HTTP/2; otherwise it settles on HTTP/1.1 - The Streamable HTTP client reconnects a dropped SSE stream with a short backoff; it gives up on a 404 or after three reconnects in a row that delivered nothing
AcpClientTransport.awaitTermination(), implemented by the Streamable HTTP and WebSocket client transports: when the transport dies, pending and later requests fail at once with the cause instead of waiting out the request timeout- JSON modules (#12): the Jackson 2 mapper moved into
acp-json-jackson2, andacp-json-jackson3addsJackson3AcpJsonMapperon Jackson 3 (3.1.5, the version Spring Boot 4.1 manages). Both write the same bytes on the wire. Proposed by @bengbengbalabalabeng - Deterministic JSON mapper selection by
AcpJsonMapperSupplier.priority(): with both modules present Jackson 3 wins, and an application’s own supplier wins over both. The system propertyacp.json.mapper.suppliernames one explicitly CancelNotificationcarries_meta;AcpSyncClient(AcpAsyncClient)is public, so both APIs can share one session
- Breaking:
acp-coredepends onjackson-annotationsonly, not onjackson-databindorjackson-core(#12).JacksonAcpJsonMapperkeeps its package and name - Single-turn enforcement is per logical session (keyed by
sessionId), because one HTTP connection carries many sessions. Stdio and WebSocket agents behave as before (#7, #9) - Unknown-field policy moved from the schema records to the mapper (#10). The default mapper stays lenient and logs each ignored property at DEBUG; a strict mapper you pass in is now honored. Reported by @KallivdH
- Request timeouts run on one shared library-owned daemon timer instead of a thread pool per session
WebSocketAcpAgentTransport(acp-websocket-jetty) is deprecated for removal. It serves a single WebSocket client;StreamableHttpAcpAgentTransportserves the WebSocket upgrade for any number of clients, andWebSocketAcpClientTransportclients connect to it unchanged
- A second
AcpClient.async(transport)orAcpClient.sync(transport)on the same stdio transport started a second agent process whose requests could only time out. This was the Spring Boot autoconfiguration failure reported in June 2026. The stdio transport now refuses a secondconnect(), and sessions surface connect failures instead of dropping them - A second prompt on a session could be rejected with
-32000or hang under CPU contention (#14): the prompt lock is now released before the response is published. Reported by @krickert WebSocketAcpAgentTransportwrote frames without waiting for the previous write, and could throw aNullPointerExceptionon close- The agent session reads
sessionIdfrom typedPromptRequestandCancelNotificationparams, so in-process transports match cancels correctly
0.17.0 (2026-08-28)
Wire-format correction. No public API change: every constructor and accessor is unchanged, and the ACP surface is identical to 0.16.1.- Fix the duplicate discriminator on the wire: every polymorphic type wrote its
typeproperty twice, sonew TextContent("hello")serialized to{"type":"text","type":"text","text":"hello"}and everysession/promptcarried a duplicate JSON key. Jackson-based peers accept duplicates; a strict parser rejects the message. The type id is now written once and is populated on deserialization (previouslynull). 27 records across 6 hierarchies
0.16.1 (2026-08-24)
Release-tooling patch. The ACP surface is identical to 0.16.0.- Every module artifact publishes a CycloneDX 1.6 SBOM (classifier
cyclonedx) covering that module’s compile and runtime scope - Each
vX.Y.Ztag now points at a commit whose POMs carry that version - SLF4J 2.0.17 → 2.0.18
0.16.0 (2026-08-24)
Maintenance dependency and release-tooling refresh. No protocol or public API changes: the ACP surface is identical to 0.15.0.- Security: Jackson 2.21.5 → 2.22.2, Jetty 12.0.37 → 12.1.12, Reactor 3.6.12 → 3.8.7
- SLF4J, Logback, JUnit 5, Mockito, Maven build plugins, Central publishing, JaCoCo and the optional OWASP dependency-check profile move to current compatible releases
0.15.0 (2026-08-21)
Correctness and supply-chain hygiene. No protocol or public API changes — a drop-in upgrade from 0.14.0.- Fix non-deterministic notification ordering — notifications are serialized through a sink drained by
concatMap, preserving arrival order (thanks @ljiro) - Drain queued notifications on graceful close instead of discarding them;
closeGracefully()now waits for the drain, bounded by the sessionrequestTimeout - Distinguish expected from anomalous notification-sink emission failures in logging
- Security: Jackson 2.21.2 → 2.21.5 and Jetty 12.0.14 → 12.0.37, clearing 17 known advisories (5 high) in the published dependency closure
- Ship the verbatim Apache License 2.0, and package LICENSE and NOTICE under
META-INFin every artifact - Run the integration tests — three
*ITclasses existed but were never executed bymvn verify - Pin GitHub Actions to commit SHAs; bound workflow jobs to 30 minutes
0.14.0 (2026-06-11)
- Docs: 0.14.0 release notes in README and CHANGELOG
- Add unstable providers/* methods
- Add messageId overloads to prompt context send methods
- Promote session config-option API to stable
- Deprecate the session-model API for removal
- Add logout and session/delete agent methods
- Add additionalDirectories and per-chunk messageId fields
- Add WebSocket edge case tests, increase max message size to 4MB
- Fix WebSocket client transport echoing agent requests back to agent
- Update version references to 0.12.0, add snapshot instructions
- Bump version to 0.13.0-SNAPSHOT
0.12.0 (2026-05-25)
- Add tutorial cross-references for module-20 and module-31 in release notes
- Add elicitation decline and cancel integration tests
- Update README with versioning policy and 0.12.0-SNAPSHOT release notes
- Add session/fork and session/set_config_option (unstable)
- Add elicitation/create and elicitation/complete (unstable)
- Add @UnstableAcpApi stability marker annotation
- Add session/list, session/close, session/resume methods
- Bump version to 0.12.0-SNAPSHOT
0.11.0 (2026-05-12)
- Remove MCP SDK dependency, add own JSON abstraction layer
- Update .gitignore with local tool config
- Bump version to 0.11.0-SNAPSHOT
0.10.0 (2026-04-10)
- Restore Duration import removed by PR #1
- Add Implementation type with clientInfo/agentInfo fields
- Add UsageUpdate support to SessionUpdate types
- Add support for UsageUpdate in SessionUpdate interface and related tests
- Update README for 0.9.0 release
- Bump version to 0.10.0-SNAPSHOT
- style: remove unused imports
0.9.0 (2026-03-31)
- Initial release.