spring-projects/spring-ai · warning

Progress notification not supported by the client!

Error message

Progress notification not supported by the client!

What it means

In DefaultMcpSyncRequestContext.progress(), when the incoming request carries no progress token (null or blank), the client cannot be notified of progress. The method logs a warning and returns immediately without sending anything; the tool invocation itself is unaffected.

Solutions

  1. Have the client include "_meta": { "progressToken": "..." } in the tools/call request
  2. Skip progress reporting or make it conditional when progress is optional
  3. Ignore the warning — it indicates a silent no-op, not a failed tool execution

Example fix

// before
ctx.progress(p -> p.progress(1).total(3));
// after
// client side: { "name": "tool", "arguments": {...}, "_meta": { "progressToken": "p1" } }
Defensive patterns

Strategy: fallback

Validate before calling

// client side: include _meta.progressToken in tools/call request
// { "name": "tool", "arguments": {...}, "_meta": { "progressToken": "p1" } }

Type guard

static boolean hasProgressToken(Object token) {
  return token != null && (!(token instanceof String s) || !s.isBlank());
}

Prevention

When it happens

Trigger: Calling ctx.progress(spec -> spec.progress(...)) inside a sync @McpTool method when the client's tool-call request did not include a progressToken in _meta.

Common situations: Testing with clients that don't attach progress tokens; combining tool code that always reports progress with clients (e.g. simple REST calls) that don't support notifications.

Related errors


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

Appendix: source

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

	@Override
	public void progress(int percentage) {
		Assert.isTrue(percentage >= 0 && percentage <= 100, "Percentage must be between 0 and 100");
		this.progress(p -> p.progress(percentage / 100.0).total(1.0).message(null));
	}

	@Override
	public void progress(Consumer<ProgressSpec> progressSpec) {

		Assert.notNull(progressSpec, "Progress spec consumer must not be null");
		DefaultProgressSpec spec = new DefaultProgressSpec();

		progressSpec.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.progress(new ProgressNotification(progressToken, spec.progress, spec.total, spec.message, spec.meta));
	}

	@Override
	public void progress(ProgressNotification progressNotification) {
		this.exchange.progressNotification(progressNotification);
	}

	// Ping

	@Override
	public void ping() {
		this.exchange.ping();
	}

View on GitHub (pinned to 98a7beda4f)