Skip to main content

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:
Ten lines, no framework dependency, nothing to configure. The lower-level builder API is there too, for dynamic handler registration or when a class and annotations don’t fit. Spring Boot, Quarkus, and Micronaut each serve the identical class: the framework finds the bean and wires its transport from configuration, nothing about the class itself changes. 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 with category: "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 by session/cancel now always ends in stop reason cancelled, 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 initialize deadline (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 explicit Unknown* 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.
One stability convention covers all of it: an API is unstable if and only if it carries @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:

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 verify and 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.
For every other change, see the CHANGELOG and the migration guide: that’s where the full, current fix list lives, not 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 plain http:// and https://, and a choice of Jackson 2 or Jackson 3. See Remote agents for the code.
Three changes need attention when upgrading:
  • acp-core no longer contains a JSON implementation. If you depend on acp-core alone, add acp-json-jackson2 or acp-json-jackson3, otherwise AcpJsonMapper.createDefault() fails with “No AcpJsonMapperSupplier found on the classpath”. acp-agent-support, acp-test, acp-websocket-jetty and acp-streamable-http-jetty already bring acp-json-jackson2.
  • A second client on an already-connected transport now fails at construction. A transport instance carries exactly one session.
  • JacksonAcpJsonMapper built from a bare new ObjectMapper() is now strict about unknown fields. Start from JacksonAcpJsonMapper.defaultObjectMapper() to keep the lenient behavior.
Added
  • Streamable HTTP transport (RFD streamable-http-websocket-transport), contributed by @kamikaz1k (#7). StreamableHttpAcpClientTransport in acp-core talks to a remote agent over HTTP POST with SSE response streams. The new acp-streamable-http-jetty module provides StreamableHttpAcpAgentTransport, a Jetty listener that serves HTTP/SSE and a WebSocket upgrade on the same path and hosts one agent per remote connection through AcpAgentFactory. Header names and path match the TypeScript and Rust SDKs
  • StreamableHttpAcpServlet is 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 needs StreamableHttpAcpAgentTransport
  • Limits and keep-alive for the HTTP agent transport (StreamableHttpAcpAgentTransportOptions): POST bodies capped at 16 MiB by default, bounded WebSocket send queues and provisional session/load streams, a : keep-alive comment 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, and acp-json-jackson3 adds Jackson3AcpJsonMapper on 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 property acp.json.mapper.supplier names one explicitly
  • CancelNotification carries _meta; AcpSyncClient(AcpAsyncClient) is public, so both APIs can share one session
Changed
  • Breaking: acp-core depends on jackson-annotations only, not on jackson-databind or jackson-core (#12). JacksonAcpJsonMapper keeps 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
Deprecated
  • WebSocketAcpAgentTransport (acp-websocket-jetty) is deprecated for removal. It serves a single WebSocket client; StreamableHttpAcpAgentTransport serves the WebSocket upgrade for any number of clients, and WebSocketAcpClientTransport clients connect to it unchanged
Fixed
  • A second AcpClient.async(transport) or AcpClient.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 second connect(), and sessions surface connect failures instead of dropping them
  • A second prompt on a session could be rejected with -32000 or hang under CPU contention (#14): the prompt lock is now released before the response is published. Reported by @krickert
  • WebSocketAcpAgentTransport wrote frames without waiting for the previous write, and could throw a NullPointerException on close
  • The agent session reads sessionId from typed PromptRequest and CancelNotification params, 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 type property twice, so new TextContent("hello") serialized to {"type":"text","type":"text","text":"hello"} and every session/prompt carried 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 (previously null). 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.Z tag 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 session requestTimeout
  • 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-INF in every artifact
  • Run the integration tests — three *IT classes existed but were never executed by mvn 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.