Skip to content

example: add example in progress #271

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

jokemanfire
Copy link
Collaborator

Motivation and Context

add a example to introduce progress

How Has This Been Tested?

Breaking Changes

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

@github-actions github-actions bot added T-documentation Documentation improvements T-dependencies Dependencies related changes T-config Configuration file changes T-examples Example code changes labels Jun 18, 2025
@schwifty-brows
Copy link

i see the "simualte getting from a stream" but to really test, i would create a stream and process the resulting stream

@schwifty-brows
Copy link

after that is added and you run the test, you should be able to see the return inconsistency

alexhancock
alexhancock previously approved these changes Jun 20, 2025
Copy link
Contributor

@alexhancock alexhancock left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@alexhancock
Copy link
Contributor

I was able to verify/successfully run the example @schwifty-brows via python3 progress_test_client.py in examples/clients/scripts

Screenshot 2025-06-20 at 11 49 45 AM

Were you running into something different than me?

@schwifty-brows
Copy link

schwifty-brows commented Jun 20, 2025 via email

@jokemanfire
Copy link
Collaborator Author

jokemanfire commented Jun 21, 2025

I think it is not rmcp's problem , I think it should be your business flow problem @schwifty-brows . And I have tested all the transport.

The current example file structure is not very good. In fact, this example is better placed in an integration test. I will modify this structure in another pr. @alexhancock

@schwifty-brows
Copy link

how should we be sending SSE messages back? the progress notification is meant to do this, but running a simple example does not consistently work

@jokemanfire
Copy link
Collaborator Author

how should we be sending SSE messages back? the progress notification is meant to do this, but running a simple example does not consistently work

I really find it difficult to reproduce the abnormal scenario you mentioned. In the example, I should have provided a relatively simple example to send progress notifications from the server and obtain notification messages from the client. If it is a problem with the basic components of MCP SDK, then I believe that integration testing can definitely reproduce it (after excluding business interference). Could you please try to provide test cases that can be reproduced after excluding business impact.

@jokemanfire jokemanfire requested a review from alexhancock June 24, 2025 07:41
@schwifty-brows
Copy link

schwifty-brows commented Jun 24, 2025

maybe i am missing something (i probably am) but in the code example, i dont see anything like this

i have a tool definition like so


 #[tool(description = "do something")]
    async fn search_warhouse(
        &self,
        #[tool(param)]
        #[schemars(description = "query")]
        query: String,
        ctx: RequestContext<RoleServer>
    ) -> Result<CallToolResult, ErrorData>
and in my example 
//inject some strings into query_results
        let mut query_results: Vec<String> = vec![];
    let mut counter = 0;
    for i in 0..query_results.len() {
        let t = query_results[i].to_string();
        let progress_param = ProgressNotificationParam {
            progress_token: ProgressToken(NumberOrString::Number(counter)),
            progress: counter,
            total: Some(query_results.len() as u32),
            message: Some("test".to_string()),
        };
        match ctx.peer.notify_progress(progress_param).await {
            Ok(_) => {
                counter += 1;
                debug!("progress notification sent");
            }
            Err(e) => {
                return Err(rmcp::Error::internal_error(
                    format!("failed to notify progress: {}", e),
                    Some(e.to_string().parse().unwrap())
                ));
            }
        }
    }

ctx.peer.notify_progress is used to send the notification. This is the problem area in question i dont see this as part of the example and where i keep getting 1-n notifications. If this is not the recommended way, that might be the problem

@alexhancock
Copy link
Contributor

This part of the example server here seems relevant, and very similar to the ctx.peer.notify_progress example you're looking for @schwifty-brows

Does that make sense? Or if not maybe it's just github communication tripping me up from understanding. I would be happy to jump on a quick video call if you want tomorrow to discuss/get clear and identify any required improvements at the SDK level.

@schwifty-brows
Copy link

Hey @alexhancock i think that would be a great idea!

Let me know your availability and I can walk you through the real world use case here.

@alexhancock
Copy link
Contributor

alexhancock commented Jun 25, 2025

Hey @alexhancock i think that would be a great idea!

Let me know your availability and I can walk you through the real world use case here.

@schwifty-brows How about 10am US eastern tomorrow? Email me (address on my profile) and we can set a meet.

@alexhancock
Copy link
Contributor

@schwifty-brows @jokemanfire I think it may be a client difference...

When I run cargo run --example clients_progress_test_client -- --transport sse it works

�[2m2025-06-25T14:36:54.750050Z�[0m �[32m INFO�[0m �[2mclients_progress_test_client�[0m�[2m:�[0m RMCP Progress Notification Test Client
�[2m2025-06-25T14:36:54.750186Z�[0m �[32m INFO�[0m �[2mclients_progress_test_client�[0m�[2m:�[0m ==========================================
�[2m2025-06-25T14:36:54.750220Z�[0m �[32m INFO�[0m �[2mclients_progress_test_client�[0m�[2m:�[0m Testing SSE Transport
�[2m2025-06-25T14:36:54.750229Z�[0m �[32m INFO�[0m �[2mclients_progress_test_client�[0m�[2m:�[0m =========================
�[2m2025-06-25T14:36:54.750237Z�[0m �[32m INFO�[0m �[2mclients_progress_test_client�[0m�[2m:�[0m SSE URL: http://127.0.0.1:8000/sse
�[2m2025-06-25T14:36:55.779656Z�[0m �[32m INFO�[0m �[1mserve_inner�[0m�[2m:�[0m �[2mrmcp::service�[0m�[2m:�[0m Service initialized as client �[3mpeer_info�[0m�[2m=�[0mSome(InitializeResult { protocol_version: ProtocolVersion("2024-11-05"), capabilities: ServerCapabilities { experimental: None, logging: None, completions: None, prompts: None, resources: None, tools: Some(ToolsCapability { list_changed: None }) }, server_info: Implementation { name: "rmcp", version: "0.1.5" }, instructions: Some("This server demonstrates progress notifications during long-running operations. Use the tools to see real-time progress updates for batch processing") })
�[2m2025-06-25T14:36:55.779944Z�[0m �[32m INFO�[0m �[2mclients_progress_test_client�[0m�[2m:�[0m Connected to server: "rmcp"
�[2m2025-06-25T14:36:55.781660Z�[0m �[32m INFO�[0m �[2mclients_progress_test_client�[0m�[2m:�[0m Available tools: ["stream_processor"]
�[2m2025-06-25T14:36:55.781674Z�[0m �[32m INFO�[0m �[2mclients_progress_test_client�[0m�[2m:�[0m Starting to process 10 records...
�[2m2025-06-25T14:36:55.782563Z�[0m �[32m INFO�[0m �[2mrmcp::service�[0m�[2m:�[0m received notification �[3mnotification�[0m�[2m=�[0mProgressNotification(Notification { method: ProgressNotificationMethod, params: ProgressNotificationParam { progress_token: ProgressToken(Number(1)), progress: 1, total: None, message: Some("H") }, extensions: Extensions })
�[2m2025-06-25T14:36:55.782662Z�[0m �[32m INFO�[0m �[2mclients_progress_test_client�[0m�[2m:�[0m Progress update [1]: 1/0 - H (elapsed: 0.0s)
�[2m2025-06-25T14:36:55.782745Z�[0m �[32m INFO�[0m �[2mrmcp::service�[0m�[2m:�[0m received notification �[3mnotification�[0m�[2m=�[0mProgressNotification(Notification { method: ProgressNotificationMethod, params: ProgressNotificationParam { progress_token: ProgressToken(Number(2)), progress: 2, total: None, message: Some("e") }, extensions: Extensions })
�[2m2025-06-25T14:36:55.782804Z�[0m �[32m INFO�[0m �[2mclients_progress_test_client�[0m�[2m:�[0m Progress update [2]: 2/0 - e (elapsed: 0.0s)
�[2m2025-06-25T14:36:55.782893Z�[0m �[32m INFO�[0m �[2mrmcp::service�[0m�[2m:�[0m received notification �[3mnotification�[0m�[2m=�[0mProgressNotification(Notification { method: ProgressNotificationMethod, params: ProgressNotificationParam { progress_token: ProgressToken(Number(3)), progress: 3, total: None, message: Some("l") }, extensions: Extensions })
�[2m2025-06-25T14:36:55.782944Z�[0m �[32m INFO�[0m �[2mclients_progress_test_client�[0m�[2m:�[0m Progress update [3]: 3/0 - l (elapsed: 0.0s)
�[2m2025-06-25T14:36:55.783056Z�[0m �[32m INFO�[0m �[2mrmcp::service�[0m�[2m:�[0m received notification �[3mnotification�[0m�[2m=�[0mProgressNotification(Notification { method: ProgressNotificationMethod, params: ProgressNotificationParam { progress_token: ProgressToken(Number(4)), progress: 4, total: None, message: Some("l") }, extensions: Extensions })
�[2m2025-06-25T14:36:55.783124Z�[0m �[32m INFO�[0m �[2mclients_progress_test_client�[0m�[2m:�[0m Progress update [4]: 4/0 - l (elapsed: 0.0s)
�[2m2025-06-25T14:36:55.783177Z�[0m �[32m INFO�[0m �[2mrmcp::service�[0m�[2m:�[0m received notification �[3mnotification�[0m�[2m=�[0mProgressNotification(Notification { method: ProgressNotificationMethod, params: ProgressNotificationParam { progress_token: ProgressToken(Number(5)), progress: 5, total: None, message: Some("o") }, extensions: Extensions })
�[2m2025-06-25T14:36:55.783216Z�[0m �[32m INFO�[0m �[2mclients_progress_test_client�[0m�[2m:�[0m Progress update [5]: 5/0 - o (elapsed: 0.0s)
�[2m2025-06-25T14:36:55.783289Z�[0m �[32m INFO�[0m �[2mrmcp::service�[0m�[2m:�[0m received notification �[3mnotification�[0m�[2m=�[0mProgressNotification(Notification { method: ProgressNotificationMethod, params: ProgressNotificationParam { progress_token: ProgressToken(Number(6)), progress: 6, total: None, message: Some(",") }, extensions: Extensions })
�[2m2025-06-25T14:36:55.783339Z�[0m �[32m INFO�[0m �[2mclients_progress_test_client�[0m�[2m:�[0m Progress update [6]: 6/0 - , (elapsed: 0.0s)
�[2m2025-06-25T14:36:55.783409Z�[0m �[32m INFO�[0m �[2mrmcp::service�[0m�[2m:�[0m received notification �[3mnotification�[0m�[2m=�[0mProgressNotification(Notification { method: ProgressNotificationMethod, params: ProgressNotificationParam { progress_token: ProgressToken(Number(7)), progress: 7, total: None, message: Some(" ") }, extensions: Extensions })
�[2m2025-06-25T14:36:55.783450Z�[0m �[32m INFO�[0m �[2mclients_progress_test_client�[0m�[2m:�[0m Progress update [7]: 7/0 -   (elapsed: 0.0s)
�[2m2025-06-25T14:36:55.783509Z�[0m �[32m INFO�[0m �[2mrmcp::service�[0m�[2m:�[0m received notification �[3mnotification�[0m�[2m=�[0mProgressNotification(Notification { method: ProgressNotificationMethod, params: ProgressNotificationParam { progress_token: ProgressToken(Number(8)), progress: 8, total: None, message: Some("w") }, extensions: Extensions })
�[2m2025-06-25T14:36:55.783549Z�[0m �[32m INFO�[0m �[2mclients_progress_test_client�[0m�[2m:�[0m Progress update [8]: 8/0 - w (elapsed: 0.0s)
�[2m2025-06-25T14:36:55.783598Z�[0m �[32m INFO�[0m �[2mrmcp::service�[0m�[2m:�[0m received notification �[3mnotification�[0m�[2m=�[0mProgressNotification(Notification { method: ProgressNotificationMethod, params: ProgressNotificationParam { progress_token: ProgressToken(Number(9)), progress: 9, total: None, message: Some("o") }, extensions: Extensions })
�[2m2025-06-25T14:36:55.783636Z�[0m �[32m INFO�[0m �[2mclients_progress_test_client�[0m�[2m:�[0m Progress update [9]: 9/0 - o (elapsed: 0.0s)
�[2m2025-06-25T14:36:55.783690Z�[0m �[32m INFO�[0m �[2mrmcp::service�[0m�[2m:�[0m received notification �[3mnotification�[0m�[2m=�[0mProgressNotification(Notification { method: ProgressNotificationMethod, params: ProgressNotificationParam { progress_token: ProgressToken(Number(10)), progress: 10, total: None, message: Some("r") }, extensions: Extensions })
�[2m2025-06-25T14:36:55.783725Z�[0m �[32m INFO�[0m �[2mclients_progress_test_client�[0m�[2m:�[0m Progress update [10]: 10/0 - r (elapsed: 0.0s)
�[2m2025-06-25T14:36:55.783777Z�[0m �[32m INFO�[0m �[2mrmcp::service�[0m�[2m:�[0m received notification �[3mnotification�[0m�[2m=�[0mProgressNotification(Notification { method: ProgressNotificationMethod, params: ProgressNotificationParam { progress_token: ProgressToken(Number(11)), progress: 11, total: None, message: Some("l") }, extensions: Extensions })
�[2m2025-06-25T14:36:55.783811Z�[0m �[32m INFO�[0m �[2mclients_progress_test_client�[0m�[2m:�[0m Progress update [11]: 11/0 - l (elapsed: 0.0s)
�[2m2025-06-25T14:36:55.783858Z�[0m �[32m INFO�[0m �[2mrmcp::service�[0m�[2m:�[0m received notification �[3mnotification�[0m�[2m=�[0mProgressNotification(Notification { method: ProgressNotificationMethod, params: ProgressNotificationParam { progress_token: ProgressToken(Number(12)), progress: 12, total: None, message: Some("d") }, extensions: Extensions })
�[2m2025-06-25T14:36:55.783893Z�[0m �[32m INFO�[0m �[2mclients_progress_test_client�[0m�[2m:�[0m Progress update [12]: 12/0 - d (elapsed: 0.0s)
�[2m2025-06-25T14:36:55.783941Z�[0m �[32m INFO�[0m �[2mrmcp::service�[0m�[2m:�[0m received notification �[3mnotification�[0m�[2m=�[0mProgressNotification(Notification { method: ProgressNotificationMethod, params: ProgressNotificationParam { progress_token: ProgressToken(Number(13)), progress: 13, total: None, message: Some("!") }, extensions: Extensions })
�[2m2025-06-25T14:36:55.783973Z�[0m �[32m INFO�[0m �[2mclients_progress_test_client�[0m�[2m:�[0m Progress update [13]: 13/0 - ! (elapsed: 0.0s)
�[2m2025-06-25T14:36:55.784108Z�[0m �[32m INFO�[0m �[2mclients_progress_test_client�[0m�[2m:�[0m Processing completed: Processed 13 records successfully
�[2m2025-06-25T14:36:55.784174Z�[0m �[32m INFO�[0m �[2mrmcp::service�[0m�[2m:�[0m task cancelled
�[2m2025-06-25T14:36:55.784195Z�[0m �[32m INFO�[0m �[2mrmcp::service�[0m�[2m:�[0m serve finished �[3mquit_reason�[0m�[2m=�[0mCancelled
�[2m2025-06-25T14:36:55.784352Z�[0m �[32m INFO�[0m �[2mclients_progress_test_client�[0m�[2m:�[0m Total progress notifications received: 13
�[2m2025-06-25T14:36:55.784370Z�[0m �[32m INFO�[0m �[2mclients_progress_test_client�[0m�[2m:�[0m Total time elapsed: 0.01s
�[2m2025-06-25T14:36:55.784383Z�[0m �[32m INFO�[0m �[2mclients_progress_test_client�[0m�[2m:�[0m SSE transport test completed successfully!

However when I use the MCP inspector as another client to test with by running

cargo run --example servers_progress_demo -- sse

and connect to it via

npx @modelcontextprotocol/inspector

I see this when I run the stream processor tool I only see one progress notification despite it processing 13 records. This is similar to what @schwifty-brows reproduces with his test client:

Screenshot 2025-06-25 at 10 36 08 AM

@jokemanfire Any ideas?

@jokemanfire
Copy link
Collaborator Author

It does seem to be related to the client, I will take a look at the inspector and compare the implementation differences.

@jokemanfire
Copy link
Collaborator Author

jokemanfire commented Jun 26, 2025

I used Wireshark to capture packets, and I can confirm that the notify packet for Rust SDK was sent. I may need to take a look at the inspector code now.
image

All the [PSH,ACK] is the data.

@jokemanfire
Copy link
Collaborator Author

jokemanfire commented Jun 26, 2025

I have add log in inspector , I can make sure the mcpProxy recived the progress data, the problem should in inspector's front end.

[mcpProxy] Received message from SERVER: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":1,"progress":1,"total":13,"message":"H"}}
[mcpProxy] Forwarded message to CLIENT: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":1,"progress":1,"total":13,"message":"H"}}
[mcpProxy] Received message from SERVER: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":2,"progress":2,"total":13,"message":"e"}}
[mcpProxy] Forwarded message to CLIENT: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":2,"progress":2,"total":13,"message":"e"}}
[mcpProxy] Received message from SERVER: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":3,"progress":3,"total":13,"message":"l"}}
[mcpProxy] Forwarded message to CLIENT: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":3,"progress":3,"total":13,"message":"l"}}
[mcpProxy] Received message from SERVER: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":4,"progress":4,"total":13,"message":"l"}}
[mcpProxy] Forwarded message to CLIENT: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":4,"progress":4,"total":13,"message":"l"}}
[mcpProxy] Received message from SERVER: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":5,"progress":5,"total":13,"message":"o"}}
[mcpProxy] Forwarded message to CLIENT: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":5,"progress":5,"total":13,"message":"o"}}
[mcpProxy] Received message from SERVER: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":6,"progress":6,"total":13,"message":","}}
[mcpProxy] Forwarded message to CLIENT: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":6,"progress":6,"total":13,"message":","}}
[mcpProxy] Received message from SERVER: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":7,"progress":7,"total":13,"message":" "}}
[mcpProxy] Forwarded message to CLIENT: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":7,"progress":7,"total":13,"message":" "}}
[mcpProxy] Received message from SERVER: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":8,"progress":8,"total":13,"message":"w"}}
[mcpProxy] Forwarded message to CLIENT: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":8,"progress":8,"total":13,"message":"w"}}
[mcpProxy] Received message from SERVER: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":9,"progress":9,"total":13,"message":"o"}}
[mcpProxy] Forwarded message to CLIENT: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":9,"progress":9,"total":13,"message":"o"}}
[mcpProxy] Received message from SERVER: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":10,"progress":10,"total":13,"message":"r"}}
[mcpProxy] Forwarded message to CLIENT: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":10,"progress":10,"total":13,"message":"r"}}
[mcpProxy] Received message from SERVER: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":11,"progress":11,"total":13,"message":"l"}}
[mcpProxy] Forwarded message to CLIENT: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":11,"progress":11,"total":13,"message":"l"}}
[mcpProxy] Received message from SERVER: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":12,"progress":12,"total":13,"message":"d"}}
[mcpProxy] Forwarded message to CLIENT: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":12,"progress":12,"total":13,"message":"d"}}
[mcpProxy] Received message from SERVER: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":13,"progress":13,"total":13,"message":"!"}}
[mcpProxy] Forwarded message to CLIENT: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":13,"progress":13,"total":13,"message":"!"}}
[mcpProxy] Received message from SERVER: {"jsonrpc":"2.0","id":4,"result":{"content":[{"type":"text","text":"Processed 13 records successfully"}],"isError":false}}
[mcpProxy] Forwarded message to CLIENT: {"jsonrpc":"2.0","id":4,"result":{"content":[{"type":"text","text":"Processed 13 records successfully"}],"isError":false}}

@jokemanfire
Copy link
Collaborator Author

Hello @olaservo If you have time, can you help me take a look?

@alexhancock
Copy link
Contributor

So just to be clear, this is looking to everyone now like a client only issue?

@schwifty-brows Did you repro this only with inspector, or with a client in your actual codebase as well?

@jokemanfire
Copy link
Collaborator Author

Sorry for the update, the issue may be due to differences in the implementation of typescript-sdk.

@alexhancock
Copy link
Contributor

@schwifty-brows Did this ever work for you with a different client?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T-config Configuration file changes T-dependencies Dependencies related changes T-documentation Documentation improvements T-examples Example code changes T-test Testing related changes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants