Skip to content

Impossible to add progressToken and use onProgress callback #220

@jblanchard-figure

Description

@jblanchard-figure

Describe the bug
When trying to add progress notifications to a request, setting the RequestOptions.onProgress lambda in the callTool method does not include progressToken in the _meta of the request.

To Reproduce
Steps to reproduce the behavior:

  1. Add tool to server that can support progress notifications by trying to extract the progress token from _meta.
RegisteredTool(
  Tool(
    name = "progressFail",
    description = "Fails with null pointer exception",
    inputSchema = Tool.Input(),
    outputSchema = Tool.Output(),
    annotations = null,
  ),
) { request ->
  val progressToken = request._meta["progressToken"]?.let { jsonElement ->
    Json.decodeFromJsonElement<ProgressToken>(jsonElement)
  }
  progressToken!! // throws NPE
}
  1. Connect a client to the server an make a call tool request like so:
client.callTool(
  CallToolRequest(
    name = "progressFail",
  ),
  RequestOptions(
    onProgress = {
      progress.progress / progress.total
    }
  )
)
  1. Server will throw NPE
  2. Try to set progressToken manually on request:
client.callTool(
  CallToolRequest(
    name = "progressFail",
    _meta = buildJsonObject {
      put("progressToken", 1234) // we don't have access to the request id here so it's impossible to associate the onProgress callback with this token
    },
  ),
  RequestOptions(
    onProgress = {
      progress.progress / progress.total // will never be called because it is associated to request id
    }
  )
)
  1. Receive log messages about a progress notification for an unknown token.

Expected behavior
I expect to be able to both register an onProgress callback on a callTool invocation, and be able to extract that token on the server to send it back with the notification.

Logs
Log of NPE when not manually setting token:

{"timestamp":"2025-08-07T21:30:58.052","level":"INFO","logger.thread_name":"docker-java-stream-1030446516","logger.name":"...","message":"{\"timestamp\":\"2025-08-08T01:30:58.043\",\"level\":\"ERROR\",\"logger.thread_name\":\"DefaultDispatcher-worker-2\",\"logger.name\":\"io.modelcontextprotocol.kotlin.sdk.shared.Protocol\",\"message\":\"Error handling request: tools/call (id: NumberId(value=4))\",\"error.stack\":\"java.lang.NullPointerException: null\\n\\tat 
...
kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)\\n\\tat kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:100)\\n\\tat kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:586)\\n\\tat kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:829)\\n\\tat kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:717)\\n\\tat kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:704)\\n\",\"error.kind\":\"java.lang.NullPointerException\"}"}

Logs when attempting to set token manually in _meta on a request:

{"timestamp":"2025-08-07T20:58:26.981","level":"ERROR","logger.thread_name":"DefaultDispatcher-worker-5 @SseMcpClientTransport.connect#385137368#23","logger.name":"io.modelcontextprotocol.kotlin.sdk.shared.Protocol","message":"Received a progress notification for an unknown token: {\"progress\":0,\"progressToken\":12345,\"_meta\":{},\"total\":5.0,\"method\":\"notifications/progress\"}"}
{"timestamp":"2025-08-07T20:58:27.983","level":"ERROR","logger.thread_name":"DefaultDispatcher-worker-5 @SseMcpClientTransport.connect#385137368#23","logger.name":"io.modelcontextprotocol.kotlin.sdk.shared.Protocol","message":"Received a progress notification for an unknown token: {\"progress\":1,\"progressToken\":12345,\"_meta\":{},\"total\":5.0,\"method\":\"notifications/progress\"}"}

Additional context
Add any other context about the problem here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions