Bug description I'm testing the progress callback feature in the MCP protocol, but no progress notifications are received on the Python client side. The tool executes successfully and returns "success", but the registered progress_callback function is never triggered.

Environment Spring AI version: 1.1.0-RC1 python-sdk version: 1.20.0

Steps to reproduce

@McpTool(description = "Test progress callback.")
public String testProgress(McpSyncRequestContext context, @McpProgressToken String progressToken) {
    log.info("progressToken: {}", progressToken);

    if (progressToken != null) {
        context.progress(p -> p.progress(0.0).total(1.0).message("Starting analysis"));
    }

    if (progressToken != null) {
        context.progress(p -> p.progress(1.0).total(1.0).message("Analysis complete"));
    }

    return "success";
}

Expected behavior:

The progress messages (“Starting analysis” and “Analysis complete”) should be sent to the client.

Actual behavior:

The progressToken is not null, and both context.progress(...) calls are executed (confirmed by logs).

However, no progress messages are received on the Python side.

async def handle_progress_message(progress: float, total: float | None, message: str | None) -> None:
    """Handle progress messages"""
    print(f"\r🔍 {message}", end='', flush=True)
    print()

async def call_tool(self, name: str, args: dict) -> Any:
    loop = self._worker_task.get_loop()
    coro = self.session.call_tool(name, progress_callback=handle_progress_message, arguments=args)

    if loop is asyncio.get_running_loop():
        return await coro

    fut: concurrent.futures.Future = asyncio.run_coroutine_threadsafe(coro, loop)
    return await asyncio.wrap_future(fut)

Expected behavior:

The function handle_progress_message() should be called twice with messages from the server.

Actual behavior:

The function is never called.

The tool call completes successfully and returns the "success" string, but no progress updates are printed.

Is there any known limitation or additional setup required to enable progress callbacks between Spring AI’s MCP implementation and mcp-python?

Comment From: myifeng

````java @McpTool(description = "get_weather", name = "get_weather") public String getWeather(McpSyncRequestContext context, @McpProgressToken String progressToken) { // Access progress token from context log.info("progressToken: {}", progressToken);

    if (progressToken != null) {
        context.info("Processing data: 0");
        context.progress(p -> p.progress(0.0).total(1.0).message("Starting analysis"));
    }

    if (progressToken != null) {
        context.info("Processing data: 1");
        context.progress(p -> p.progress(1.0).total(1.0).message("Analysis complete"));
    }
    return "success";
}

```python
import asyncio

from mcp import ClientSession
from mcp.client.sse import sse_client
from mcp.types import LoggingMessageNotificationParams


async def logging_callback(params: LoggingMessageNotificationParams):
    print(f"\n[Server Log - {params.level.upper()}] {params.data}")

async def progress_callback(progress: float, total: float | None, message: str | None) -> None:
    print(f"\n[Progress {progress}/{total}]: {message}")

async def main():
  async with sse_client("http://localhost:8080/sse") as (read_stream, write_stream):
       async with ClientSession(
           read_stream, 
           write_stream, 
           logging_callback=logging_callback
        ) as session:
            await session.initialize()
            response = await session.list_tools()
            tools = response.tools

            # Call get_weather tool
            weather_result = await session.call_tool(
                name="get_weather", 
                arguments={"latitude": 32.0853, "longitude": 34.7818}, 
                progress_callback=progress_callback
            )
            print("\nWeather:", weather_result)

if __name__ == "__main__":
    asyncio.run(main())

Only Log, no progress

[Server Log - INFO] Processing data: 0

[Server Log - INFO] Processing data: 1

Weather: meta=None content=[TextContent(type='text', text='success', annotations=None, meta=None)] structuredContent=None isError=False

Comment From: myifeng

Root cause: Type mismatch for progressToken. The Python client sends progressToken as a number (e.g. 2), but spring-ai converts/returns it as a string ("2"). The mcp-python SDK maps progress callbacks using numeric keys, so when the server returns a string token the SDK fails to find the registered callback and progress_callback is never invoked.

Server:

Image

Client:

SessionMessage(message=JSONRPCMessage(root=JSONRPCNotification(method='notifications/progress', params={'progressToken': '2', 'progress': 0.0, 'total': 1.0, 'message': 'Starting analysis', '_meta': {}}, jsonrpc='2.0')), metadata=None)

Image

Comment From: myifeng

https://github.com/modelcontextprotocol/java-sdk/issues/659

Comment From: jamesward

I'm running into an issue with this in Spring AI 1.1 GA. Did this fix get into the 1.1 release? If so maybe it is something else. On the tool call in MCP Inspector I get argument type mismatch with public int divide(int x, int y, @McpProgressToken String progressToken)

Comment From: myifeng

I'm running into an issue with this in Spring AI 1.1 GA. Did this fix get into the 1.1 release? If so maybe it is something else. On the tool call in MCP Inspector I get argument type mismatch with public int divide(int x, int y, @McpProgressToken String progressToken)

@McpProgressToken Object progressToken

Comment From: jamesward

Thanks. I guess that is the only way in Java to handle the Int | String sum type. Can Java annotations force the type they are applied on to be something specific? Probably wouldn't work for Object but if it were possible, the MCP Java SDK could have an IntOrString class which @McpProgressToken would require (to be spec compliant).