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>
This change adds Jackson 3 support and aligns package naming in the existing Jackson 2 module.
Specific changes:
* Deprecated classes for removal in `io.modelcontextprotocol.json.jackson`/`io.modelcontextprotocol.json.schema.jackson`
* Copied the above to `io.modelcontextprotocol.json.jackson2`/`io.modelcontextprotocol.json.schema.jackson2` in non-deprecated form.
* Added tests for the default McpJsonMapper and JsonSchemaValidator
The mcp module packages dependencies but has no sources, causing
Maven release failures. Skip source and javadoc JAR generation
to fix deployment errors.
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
* extract mcp-core
- This change extracts classes previously in `mcp` to `mcp-core`; a new module which does not depend on `mcp-json-jackon2`.
- `mcp` module is now an umbrella module that brings `mcp-json-jackon2` and `mcp-core`
* add mcp-core to bom
BREAKING CHANGE: All source code in the previously `mcp` module is moved to the `mcp-core`. the `mcp` now is just an aggregation for `mcp-core` + `mcp-json-jackson2` for backward compatibility.
This change won't affect the end users, but will cause conflicts for the existing PRs.
This pull request creates two modules, `mcp-json` and `mcp-json-jackson`. It removes the `com.fasterxml.jackson.core:jackson-databind` and `com.networknt:json-schema-validator` dependencies from the `mcp` module. The `mcp` module now only depends on `com.fasterxml.jackson.core:jackson-annotations`.
To use Jackson, you have to add `mcp-jackson` to your dependencies in addition to `mcp`. I added the dependency `mcp-jackson` to both `mcp-spring-mvc` and `mcp-spring-webflux` to avoid a breaking change in those modules.
It provides two [SPI](https://docs.oracle.com/javase/tutorial/sound/SPI-intro.html) `JsonSchemaValidatorSupplier` and `JacksonJsonSchemaValidatorSupplier` to allow easy replacement for consumers who don't want to use Jackson.
This pull request also ensures no `McpJsonMapper` is instantiated if one is provided via a builder method. Only if the builders don't receive a `McpJsonMapper` mapper, one is instantiated in the `build` method of the builder.
The logic behind this is to allow frameworks to provide a `McpJsonMapper` mapper singleton implementation and feed it to the builders without paying the price of instantiating `McpJsonMappers`, which will not be used. The goal is to be able to use the `ObjectMapper` singleton of an application also for the MCP code.
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
- Change CallToolResult.structuredContent type from Map<String,Object> to Object
to support both objects and arrays
- Update JsonSchemaValidator to validate any Object type, not just Maps
- Add test cases for array-type structured output validation
- Fix type casting in existing tests to handle the more generic Object type
- Deprecate CallToolResult constructors in favor of builder pattern
- Update server implementations to use CallToolResult builder
This allows tools to return arrays as structured content, not just objects,
which is required by the MCP specification for tools with array-type output schemas.
It is realated to MPC spec fix: https://github.com/modelcontextprotocol/modelcontextprotocol/issues/834Fixes#550
BREAKING CHANGE!
Migration Guide:
----------------
1. If you're accessing CallToolResult.structuredContent():
- Add explicit casting when you know it's a Map:
Before: result.structuredContent().get("key")
After: ((Map<String,Object>) result.structuredContent()).get("key")
- Or check the type first:
if (result.structuredContent() instanceof Map) {
Map<String,Object> map = (Map<String,Object>) result.structuredContent();
// use map
} else if (result.structuredContent() instanceof List) {
List<?> list = (List<?>) result.structuredContent();
// use list
}
2. If you're creating CallToolResult instances:
- Switch to using the builder pattern:
Before: new CallToolResult(content, isError, structuredContent)
After: CallToolResult.builder()
.content(content)
.isError(isError)
.structuredContent(structuredContent)
.build()
3. If you're implementing JsonSchemaValidator:
- Update your validate() method signature:
Before: validate(Map<String,Object> schema, Map<String,Object> structuredContent)
After: validate(Map<String,Object> schema, Object structuredContent)
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
Add @JsonInclude(JsonInclude.Include.NON_ABSENT) to ResourcesUpdatedNotification
and to LoggingMessageNotification
This ensures that absent (null/Optional.empty()) fields are excluded from JSON
serialization, preventing potential serialization issues with these MCP notification types.
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
This ensures that when a tool handler returns an error result, the structured
output schema validation is skipped, preventing validation failures on error
responses that don't conform to the expected output schema.
- Add validation bypass when CallToolResult.isError() is true in async/stateless servers
- Fix async tool handler chaining to properly use then() instead of block()
- Add comprehensive tests for structured output with in-handler errors
- Improve error handling to use proper JSON-RPC error codes for unknown tools
- Add findRootCause utility method for better error diagnostics
- Increase test timeouts for stability in StdioMcp client tests. 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.
Resolves#538
Related to #422
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
- Check if response.id() is not null before processing in MCP session classes
- Log error when MCP response lacks session ID to warn about potential memory leaks
- Improve error handling in McpStreamableServerSession with proper error codes
The missing null check could lead to memory leaks as pending requests
would never be completed when responses lack session IDs. This fix ensures
proper handling of such cases with appropriate error logging.
Resolves#506
Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
- Add try-finally blocks to guarantee server cleanup on test completion
- Call closeGracefully().block() to ensure synchronous shutdown
- Use try-with-resources for client lifecycle management where applicable
- Prevent resource leaks and potential test flakiness
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
- Add filter to exclude resources with template parameters ({}) from resources/list
- Template resources should only appear in resources/templates/list per MCP spec
- Add comprehensive test coverage for resource/template separation
- Update mock transport utilities for better test support
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
- Upgrade Docker test server image from v2 to v3 across all test files
- Updates all test files to use the latest version of the mcp-everything-server
Docker image (v3) for integration testing.
- Fix race condition in async client tests by not advertising roots capability during initialization
- Prevents server from listing roots during init which could cause timing issues when disconnecting immediately after initialization
- Applied fix to AbstractMcpAsyncClientResiliencyTests (both mcp and mcp-test modules) and HttpSseMcpAsyncClientLostConnectionTests
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
Co-authored-by: Daniel Garnier-Moiroux <git@garnier.wf>
- Add integration tests for transport context propagation between MCP clients and servers
- Test both sync and async server implementations across all transport types (stateless, streamable, SSE)
- Cover Spring WebFlux and WebMVC environments with dedicated test suites
- Validate context flow through HTTP headers for authentication, correlation IDs, and metadata
- Rename existing McpTransportContextIntegrationTests to SyncServerMcpTransportContextIntegrationTests for clarity
- Add proper resource cleanup for async clients in teardown methods
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
- This allows reusing the containerized MCP server for all tests in a
single class, significantly speeding up the tests, roughly 10x.
Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
* McpSyncClient: introduce McpTransportContext
- McpSyncClient should be considered thread-agnostic, and therefore
consumers cannot rely on thread locals to propagate "context", e.g.
pass down the Servlet request reference in a server context.
- This PR introduces a mechanism for populating an McpTransportContext
before executing client operations, and reworks the HTTP request
customizers to leverage that McpTransportContext.
- Move McpTransportContext from server to common package for shared client/server usage
- Make McpTransportContext immutable by removing put() and copy() methods
- Add static create() factory method for creating contexts with predefined data
- Update McpTransportContextExtractor to return context instead of modifying one
- Replace DefaultMcpTransportContext mutable implementation with immutable version
- Update all transport implementations to use McpTransportContext.EMPTY as default
- Rename *HttpRequestCustomizer -> *HttpClientRequestCustomizer
- Add end-to-end McpTransportContextIntegrationTests
- This PR introduces a breaking change to the Sync/Async request
customizers.
Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
- Move Mcp(Async)HttpRequestCustomizer from client.transport to client.transport.customizer
- Rename (Async)HttpRequestCustomizer to Mcp(Async)HttpRequestCustomizer
- Add DelegatingMcpAsyncHttpRequestCustomizer and DelegatingMcpSyncHttpRequestCustomizer for composing multiple customizers
- Update all references across transport classes and tests
- Improve package organization and naming consistency with MCP prefix
- Add McpTransportContextExtractor to WebFlux/WebMVC SSE and Streamable transport providers
- Enable extraction of HTTP transport metadata (headers, etc.) for use during request processing
- Pass transport context through reactive context chain using McpTransportContext.KEY
- Add contextExtractor() builder methods for configuring custom extractors
- Update HttpServlet transport providers with same context extraction capability
- Modify McpServerSession to properly propagate transport context to handlers
- Add test coverage with TEST_CONTEXT_EXTRACTOR in integration tests
This allows MCP feature implementations to access HTTP transport level metadata
that was present at request time, enabling use cases like authentication,
request tracing, and custom header processing.
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
Co-authored-by: Christian Tzolov <christian.tzolov@broadcom.com>
Co-authored-by: Dariusz Jędrzejczyk <dariusz.jedrzejczyk@broadcom.com>
Remove LoggingCapabilities from McpStatelessServerFeatures.Async constructor
as stateless servers do not support setLogging operations. This aligns the
async implementation with the sync implementation which already has logging
disabled.
Follows up on #463
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
- Add hasRequestedDemand volatile boolean flag to AggregateSubscriber and BodilessResponseLineSubscriber
- Modify hookOnSubscribe to request Long.MAX_VALUE only on first demand request
- Guard event emission in hookOnComplete with hasRequestedDemand check
- Prevents unnecessary data processing when no downstream demand exists
- Improves backpressure handling and resource efficiency
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
Ensure PromptReference equality is based solely on identifier and type fields, ignoring other fields like title
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
- Change LoggingCapabilities from default-initialized to nullable in ServerCapabilities
- Add check if server logging is enabled in McpAsyncClient before setting logging level
- Ensure McpAsyncServer always enables logging capabilities when built
- Ensure McpStatelessAsyncServer has disabled logging capability by default
- Update tests to verify logging capabilities can be null
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
Co-authored-by: Christian Tzolov <christian.tzolov@broadcom.com>
Implements the MCP spec guidelines for streamable HTTP (re)initialization:
- Server MAY terminate session and MUST respond with HTTP 404 for terminated session IDs
- Client MUST start new session when receiving HTTP 404 for requests with session ID
Changes:
- Replace generic McpError with McpTransportException for transport-layer errors
- Only throw McpTransportSessionNotFoundException when session ID is present in request
(per spec: 404 with session ID means session terminated, without means general error)
- Enhance error messages with more context (status codes, response events)
- Use RuntimeException for non-transport specific SSE endpoint failures
- Ensure consistent error handling across HTTP client transports
- Improve error handling with standard Java exceptions.
Replace generic McpError with appropriate standard exceptions:
- Use IllegalArgumentException for invalid input parameters
- Use IllegalStateException for state-related issues
- Use RuntimeException wrapper for initialization failures
- Use McpError.builder() with proper error codes for protocol errors
Fixes#459
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
- Replace inline StepVerifier assertions with AtomicReference pattern for better testability
- Add assertWith() usage for cleaner assertion blocks in async tests
- Simplify reactive chains using doOnNext() and thenReturn() patterns
- Remove unnecessary Thread.sleep() from elicitation handler
- Improve variable naming (rootsRef → toolsRef) for clarity
- Update timeout error message assertions to be more specific
- Clean up code formatting and remove redundant comments
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>