spring-projects/spring-ai · warning

Progress notification not supported by the client!

Error message

Progress notification not supported by the client!

What it means

Inside DefaultMcpAsyncRequestContext.sample(), the context checks whether the incoming MCP request carried a progress token. If the client did not provide one (null or empty string), it cannot send progress notifications for the sampling call, so a warning is logged and sampling proceeds without progress updates. This is not an exception; the sampling request still executes.

Solutions

  1. Have the client include a progressToken in the request _meta when calling the tool so progress can be reported
  2. Guard progress reporting in tool code: only call progress/report when the client provided a token
  3. Ignore the warning if progress reporting is optional for your use case — sampling still works

Example fix

// before
ctx.sample(s -> s.prompt("Think hard")); // always attempts progress
// after: make client send progressToken, or accept silent sampling
String token = request.meta() != null ? request.meta().get("progressToken") : null; // client must supply it
Defensive patterns

Strategy: fallback

Validate before calling

// client side, before calling the tool:
if (wantProgress) {
  request.params().put("_meta", Map.of("progressToken", "sampling-1"));
}

Type guard

static boolean clientSupportsProgress(Object progressToken) {
  if (progressToken == null) return false;
  return !(progressToken instanceof String s) || !s.isBlank();
}

Prevention

When it happens

Trigger: Calling ctx.sample(...) from an async tool method where the MCP client that issued the tool request did not set a progress token on the request (e.g. sent without a _meta/progressToken).

Common situations: Testing tools with clients (or MCP inspectors/simple HTTP clients) that never attach progress tokens; LLM clients that do not support progress notifications while the tool code unconditionally reports progress.

Related errors


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

Appendix: source

Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/context/DefaultMcpAsyncRequestContext.java:193

		return Mono.just(!(this.exchange.getClientCapabilities() == null
				|| this.exchange.getClientCapabilities().sampling() == null));
	}

	@Override
	public Mono<CreateMessageResult> sample(String... messages) {
		return this.sample(s -> s.message(messages));
	}

	@Override
	public Mono<CreateMessageResult> sample(Consumer<SamplingSpec> samplingSpec) {
		Assert.notNull(samplingSpec, "Sampling spec consumer must not be null");
		DefaultSamplingSpec spec = new DefaultSamplingSpec();
		samplingSpec.accept(spec);

		var progressToken = this.request.progressToken();

		if (progressToken == null || (progressToken instanceof String pt && !Utils.hasText(pt))) {
			logger.warn("Progress notification not supported by the client!");
		}
		return this.sample(McpSchema.CreateMessageRequest
			.builder(spec.messages, spec.maxTokens != null && spec.maxTokens > 0 ? spec.maxTokens : 500)
			.modelPreferences(spec.modelPreferences)
			.systemPrompt(spec.systemPrompt)
			.temperature(spec.temperature)
			.stopSequences(spec.stopSequences.isEmpty() ? null : spec.stopSequences)
			.includeContext(spec.includeContextStrategy)
			.meta(spec.metadata.isEmpty() ? null : spec.metadata)
			.progressToken(progressToken)
			.meta(spec.meta.isEmpty() ? null : spec.meta)
			.build());
	}

	@Override
	public Mono<CreateMessageResult> sample(CreateMessageRequest createMessageRequest) {

		return this.sampleEnabled().flatMap(enabled -> {

View on GitHub (pinned to 98a7beda4f)