Skip to content
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

Unable to access progress token in McpTool #67

Closed
aaronpowell opened this issue Mar 23, 2025 · 6 comments · Fixed by #99
Closed

Unable to access progress token in McpTool #67

aaronpowell opened this issue Mar 23, 2025 · 6 comments · Fixed by #99
Labels
enhancement New feature or request

Comments

@aaronpowell
Copy link
Contributor

Is your feature request related to a problem? Please describe.
I'm attempting to build out a .NET implementation of server-everything and one of the features is the Long Running Operation. This requires access to a progress token (https://github.com/modelcontextprotocol/servers/blob/e328131d99847e1eae33c7a6a8156fd217cf984f/src/everything/everything.ts#L406) to provide notifications back to the client.

There does not appear to be a way to access that in the McpTool method.

Describe the solution you'd like
I think there should be a way to have an argument to the McpTool method that is bound to the request context (or the equivalent _meta property from TypeScript), in the same way you can have a HttpRequest on minimal API.

Describe alternatives you've considered
I've looked at the CallToolRequestParams when creating your own CallToolHandler callback but I don't think you can get to it through that either.

Additional context
Sample Code - https://github.com/aaronpowell/modelcontextprotocol-csharp-sdk/blob/dotnet-everything/samples/EverythingServer/Tools/LongRunningTool.cs

@aaronpowell aaronpowell added the enhancement New feature or request label Mar 23, 2025
@stephentoub
Copy link
Contributor

I'm in the progress of addressing this.

@stephentoub
Copy link
Contributor

(or the equivalent _meta property from TypeScript

The CallToolRequestParams is available to an McpServerTool now as of #89, so if _meta is exposed on that, this issue will be addressed.

@stephentoub stephentoub removed their assignment Mar 24, 2025
@aaronpowell
Copy link
Contributor Author

Just playing around with the changes in #89 and it's not exposing the _meta property from the incoming request.

Here's a screenshot of the request running:

Image

In the jsonString variable we can see the _meta is available, along with the progressToken, but the CallToolRequestParams doesn't deserialize that property.

If we added it there we can expose it.

@aaronpowell
Copy link
Contributor Author

If I'm reading the JSON schema correctly, part of this is coming from here: https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json#L771-L806

The JSONRPCRequest type defines the _meta property on params as expected, and the description of it matches the description in the TypeScript SDK and Python SDK implementations (probably the others, I didn't dig that far).

Going through the Python SDK, it seems that they use a base class for many of the request types (which has that property on it), so would it make sense to create a base class in C# that has the _meta property deserialized to it?

@aaronpowell
Copy link
Contributor Author

Created a local branch where I deserialize the _meta property and this code now works:

[McpServerToolType]
public static class LongRunningTool
{
    [McpServerTool, Description("Demonstrates a long running operation with progress updates")]
    public static async Task<string> LongRunningOperation(
        IMcpServer server,
        RequestContext<CallToolRequestParams> requestParams,
        int duration = 10,
        int steps = 5)
    {
        var stepDuration = duration / steps;
        var progressToken = requestParams?.Params?.Meta?.ProgressToken;

        for (int i = 1; i < steps + 1; i++)
        {
            await Task.Delay(stepDuration * 1000);

            if (progressToken is not null && server is not null)
            {
                // Send progress update
                await server.SendMessageAsync(new JsonRpcNotification
                {
                    Method = "notifications/progress",
                    Params = new
                    {
                        progressToken,
                        total = steps,
                        progress = i
                    }
                });
            }
        }

        // Return the result
        return $"Operation completed in {duration} seconds with {steps} steps.";
    }
}

Would you like me to PR that on top of #89 (the deserialization, not the whole "everything server")?

aaronpowell added a commit to aaronpowell/modelcontextprotocol-csharp-sdk that referenced this issue Mar 25, 2025
@stephentoub
Copy link
Contributor

not the whole "everything server"

Would it make sense to add the everything server, in samples or tests or something?

stephentoub added a commit that referenced this issue Mar 26, 2025
…#99)

* Adding a base class for request params that exposes the progressToken

This aligns more with the type structure see in the other SDK's (eg: https://github.com/modelcontextprotocol/python-sdk/blob/main/src/mcp/types.py#L41) while also ensuring they are exposing the JSONRPCRequest (https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json#L771-L806) data.

Storing progressToken as an object as it could be an int or string (per https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json#L1268-L1274).

Fixes #67

* Using usings

* Apply suggestions from code review

---------

Co-authored-by: Stephen Toub <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
2 participants