Recent changes don't coerce null completion arguments to empty lists so we have
to check for null when handling prompt completions.
Resolves#932
Signed-off-by: Dariusz Jędrzejczyk <2554306+chemicL@users.noreply.github.com>
The MCP specification evolves continuously; domain types must absorb
new fields and subtypes without breaking existing clients or servers.
On the 1.x line this is structurally prevented by sealed interfaces,
which make it impossible to add a permitted subtype without breaking
exhaustive pattern-match switch expressions in caller code. This
commit opens the 2.0 release line, where those constraints are lifted
and serialization is made self-contained — independent of any global
ObjectMapper configuration.
Breaking changes for users migrating from 1.x
- Sealed interfaces removed from JSONRPCMessage, Request, Result,
Notification, ResourceContents, CompleteReference and Content.
Exhaustive switch expressions over these types must add a default
branch.
- Prompt(name, description, null) no longer silently coerces null
arguments to an empty list. Use Prompt.withDefaults() to preserve
the previous behaviour.
- CompleteCompletion.total and .hasMore are now absent from the wire
when not set, rather than being emitted as null.
- ServerParameters no longer carries Jackson annotations; it is an
internal configuration class, not a wire type.
What now works that did not before
- CompleteReference polymorphic dispatch (PromptReference vs
ResourceReference) works through a plain readValue or convertValue
call — no hand-rolled map inspection required.
- LoggingLevel deserialization is lenient: unknown level strings
produce null instead of throwing.
- All domain records now tolerate unknown JSON fields, so a client
built against an older SDK version will not fail when a newer server
sends fields it does not yet recognise.
- Null optional fields are consistently absent from serialized output
regardless of ObjectMapper configuration.
Documentation
- CONTRIBUTING adds an "Evolving wire-serialized records" section: a
9-rule recipe and example for adding a field safely.
- MIGRATION-2.0 documents all breaking changes listed above.
Follow-up coming next
Several spec-required fields (e.g. JSONRPCError.code/message,
ProgressNotification.progress, CreateMessageRequest.maxTokens,
CallToolResult.content) are stored as nullable Java types without a
null guard. If constructed with null, the NON_ABSENT rule silently
omits them, producing invalid wire JSON without throwing. Fix: compact
canonical constructors with Assert.notNull, following the pattern
already in JSONRPCRequest.
Signed-off-by: Dariusz Jędrzejczyk <2554306+chemicL@users.noreply.github.com>
Both HttpClientSseClientTransport and HttpClientStreamableHttpTransport
set Content-Type to 'application/json' without specifying the charset.
While Java's BodyPublishers.ofString() uses UTF-8 by default, the
missing charset in the header can cause the server to interpret the
request body using a different encoding (e.g., ISO-8859-1), corrupting
non-ASCII characters such as Chinese tool names.
Explicitly set Content-Type to 'application/json; charset=utf-8' in
POST requests on both client transports.
Fixes#260
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Daniel Garnier-Moiroux <git@garnier.wf>
Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
Deprecate Builder.customizeRequest() in HttpClientSseClientTransport and HttpClientStreamableHttpTransport
customizeRequest() executes its consumer once at build time, freezing
headers into the shared requestBuilder. This silently breaks OAuth
token refresh scenarios where the Authorization header needs to be
updated after the transport is built.
Add @Deprecated and update Javadoc to clarify the build-time-only
semantics and guide users toward httpRequestCustomizer() or
asyncHttpRequestCustomizer() which run on every request.
Closes#788
Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
Resolves#356
Clarify the two-tier error model:
- Recoverable tool errors: use CallToolResult with isError(true)
- Protocol-level errors: throw McpError / let exceptions propagate as JSON-RPC errors
Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
Clients can now subscribe to specific resources and receive targeted
notifications when those resources change. Previously, calling
`notifyResourceUpdated` on the server would broadcast the notification
to every connected client regardless of interest — now only sessions
that have explicitly subscribed to a given resource URI receive the
update, making resource change propagation both correct and efficient.
The subscription lifecycle is fully handled: clients can subscribe and
unsubscribe at any time, and the server cleans up subscription state
when a session closes.
Supersedes #838.
Resolves#837, #776.
---------
Signed-off-by: Dariusz Jędrzejczyk <dariusz.jedrzejczyk@broadcom.com>
- The server-servlet app depends on mcp, which must be either installed
or included in the compile artifact for `mvn exec:java` to pick it up.
- Change the build instructions to build from root, use a `-pl` flag to
target the servlet app.
- Disable the exec plugin from the root pom.
Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
Add governance documentation required for SEP-1730 tier compliance:
- DEPENDENCY_POLICY.md: Conservative update policy for Maven dependencies
- VERSIONING.md: SemVer policy with breaking/non-breaking definitions
- ROADMAP.md: 2025-11-25 spec implementation focus and v1.x development
- .github/dependabot.yml: Monthly updates with frozen production dependencies
This mirrors the TypeScript SDK PR structure while being adapted for the Java context.
Signed-off-by: Dariusz Jędrzejczyk <dariusz.jedrzejczyk@broadcom.com>
The Spring-specific transport modules (mcp-spring-webflux,
mcp-spring-webmvc) have been moved out of the MCP Java SDK into the
Spring AI project (org.springframework.ai group), effective with
MCP Java SDK 1.0 and Spring AI 2.0. This is a breaking change.
- Delete mcp-spring-webflux and mcp-spring-webmvc source modules
- Remove both artifacts from mcp-bom and root pom.xml module list
- Update docs and README
- Add blog post explaining the breaking change with before/after
migration examples
Resolves: #127
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
The initialize timeout was too short to be able to download the server
with NPX. As stated in the javadoc of `StdioMcpSyncClientTests`:
> These tests use npx to download and run the MCP "everything" server
> locally. The first test execution will download the everything server
> scripts and cache them locally, which can take more than 15 seconds.
> Subsequent test runs will use the cached version and execute faster.
Since the download happens on calling "connect", it is triggered during
the initialization of the client.
Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
Update project version across all POM files, documentation, and CI
workflow to prepare for the 1.0.x release
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>