{"record":{"id":"846962f55f55448e","repo":"spring-projects/spring-ai","slug":"progress-notification-not-supported-by-the-client","errorCode":null,"errorMessage":"Progress notification not supported by the client!","messagePattern":"Progress notification not supported by the client!","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/context/DefaultMcpAsyncRequestContext.java","lineNumber":193,"sourceCode":"\t\treturn Mono.just(!(this.exchange.getClientCapabilities() == null\n\t\t\t\t|| this.exchange.getClientCapabilities().sampling() == null));\n\t}\n\n\t@Override\n\tpublic Mono<CreateMessageResult> sample(String... messages) {\n\t\treturn this.sample(s -> s.message(messages));\n\t}\n\n\t@Override\n\tpublic Mono<CreateMessageResult> sample(Consumer<SamplingSpec> samplingSpec) {\n\t\tAssert.notNull(samplingSpec, \"Sampling spec consumer must not be null\");\n\t\tDefaultSamplingSpec spec = new DefaultSamplingSpec();\n\t\tsamplingSpec.accept(spec);\n\n\t\tvar progressToken = this.request.progressToken();\n\n\t\tif (progressToken == null || (progressToken instanceof String pt && !Utils.hasText(pt))) {\n\t\t\tlogger.warn(\"Progress notification not supported by the client!\");\n\t\t}\n\t\treturn this.sample(McpSchema.CreateMessageRequest\n\t\t\t.builder(spec.messages, spec.maxTokens != null && spec.maxTokens > 0 ? spec.maxTokens : 500)\n\t\t\t.modelPreferences(spec.modelPreferences)\n\t\t\t.systemPrompt(spec.systemPrompt)\n\t\t\t.temperature(spec.temperature)\n\t\t\t.stopSequences(spec.stopSequences.isEmpty() ? null : spec.stopSequences)\n\t\t\t.includeContext(spec.includeContextStrategy)\n\t\t\t.meta(spec.metadata.isEmpty() ? null : spec.metadata)\n\t\t\t.progressToken(progressToken)\n\t\t\t.meta(spec.meta.isEmpty() ? null : spec.meta)\n\t\t\t.build());\n\t}\n\n\t@Override\n\tpublic Mono<CreateMessageResult> sample(CreateMessageRequest createMessageRequest) {\n\n\t\treturn this.sampleEnabled().flatMap(enabled -> {","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/context/DefaultMcpAsyncRequestContext.java#L175-L211","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Have the client include a progressToken in the request _meta when calling the tool so progress can be reported","Guard progress reporting in tool code: only call progress/report when the client provided a token","Ignore the warning if progress reporting is optional for your use case — sampling still works"],"exampleFix":"// before\nctx.sample(s -> s.prompt(\"Think hard\")); // always attempts progress\n// after: make client send progressToken, or accept silent sampling\nString token = request.meta() != null ? request.meta().get(\"progressToken\") : null; // client must supply it","handlingStrategy":"fallback","validationCode":"// client side, before calling the tool:\nif (wantProgress) {\n  request.params().put(\"_meta\", Map.of(\"progressToken\", \"sampling-1\"));\n}","typeGuard":"static boolean clientSupportsProgress(Object progressToken) {\n  if (progressToken == null) return false;\n  return !(progressToken instanceof String s) || !s.isBlank();\n}","tryCatchPattern":null,"preventionTips":["Always attach a progressToken in request _meta when progress matters","Treat progress as best-effort in tool code","Verify client support for notifications/progress before relying on it"],"tags":["spring-ai","mcp","progress-notification","sampling","async-context"],"backgroundTag":"feature-not-enabled","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}