spring-projects/spring-ai · warning

Notification: + sentMessage + received non-compliant respons

Error message

Notification: + sentMessage + received non-compliant response: + responseMessage

What it means

A warning in directResponseFlux when an HTTP POST returning a direct (non-stream) response body gets a body even though the sent message was a JSON-RPC notification. Per the MCP Streamable HTTP spec, notifications must receive 202 with no body, so any non-empty body is flagged as a non-compliant response and the flux completes normally, discarding the body.

Source

Thrown at mcp/transport/mcp-spring-webflux/src/main/java/org/springframework/ai/mcp/client/webflux/transport/WebClientStreamableHttpTransport.java:519

		return response.statusCode().isSameCodeAs(HttpStatus.METHOD_NOT_ALLOWED);
	}

	private static boolean isEventStream(ClientResponse response) {
		return response.statusCode().is2xxSuccessful() && response.headers().contentType().isPresent()
				&& response.headers().contentType().get().isCompatibleWith(MediaType.TEXT_EVENT_STREAM);
	}

	private static String sessionIdOrPlaceholder(McpTransportSession<?> transportSession) {
		return transportSession.sessionId().orElse(MISSING_SESSION_ID);
	}

	private Flux<McpSchema.JSONRPCMessage> directResponseFlux(McpSchema.JSONRPCMessage sentMessage,
			ClientResponse response) {
		return response.bodyToMono(String.class).<Iterable<McpSchema.JSONRPCMessage>>handle((responseMessage, s) -> {
			try {
				if (sentMessage instanceof McpSchema.JSONRPCNotification) {
					if (logger.isWarnEnabled()) {
						logger.warn("Notification: " + sentMessage + " received non-compliant response: "
								+ (Utils.hasText(responseMessage) ? responseMessage : "[empty]"));
					}
					s.complete();
				}
				else {
					McpSchema.JSONRPCMessage jsonRpcResponse = McpSchema.deserializeJsonRpcMessage(this.jsonMapper,
							responseMessage);
					s.next(List.of(jsonRpcResponse));
				}
			}
			catch (IOException e) {
				s.error(new McpTransportException(e));
			}
		}).flatMapIterable(Function.identity());
	}

	private Flux<McpSchema.JSONRPCMessage> newEventStream(ClientResponse response, String sessionRepresentation) {
		McpTransportStream<Disposable> sessionStream = new DefaultMcpTransportStream<>(this.resumableStreams,

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Fix the server (or update its MCP transport) to return HTTP 202 with an empty body for notifications
  2. Check intermediary proxies/gateways for response body injection or status rewriting
  3. Ignore the warning if harmless, but verify notifications are actually processed server-side
  4. Test with the reference MCP server implementation to isolate compliance issues

Example fix

// before
// server: return ok().body("accepted", String.class) for notifications
// after
// server: return ResponseEntity.accepted().build(); // 202, no body for notifications
Defensive patterns

Strategy: fallback

Type guard

boolean isNotification(McpSchema.JSONRPCMessage m) {
    return m instanceof McpSchema.JSONRPCNotification;
}
// only send notifications expecting no response body

Prevention

When it happens

Trigger: Server responds 200 with a JSON body to a notification POST; a proxy rewrites 202 responses into 200 with a body; server transport implementation not following the notification-202 rule.

Common situations: Custom or hand-rolled MCP servers replying to notifications; gateway/proxy middleware adding response bodies; older server versions predating strict Streamable HTTP compliance.

Related errors


AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11). Data as JSON: /api/errors/9de1d6d45c1387fe. Report an issue: GitHub.