Skip to content

Resource subscriptions not working with Streamable HTTP transport #693

@mikekistler

Description

@mikekistler

Describe the bug

I am registering my subscribe handler like this:

builder.Services.AddMcpServer()
    .WithHttpTransport(options =>
        // Configure session timeout
        options.IdleTimeout = Timeout.InfiniteTimeSpan // Never timeout
    )
    .WithResources<LiveResources>()
    .WithSubscribeToResourcesHandler((context, token) =>
        {
            if (context.Params?.Uri is string uri)
            {
                ResourceManager.Subscriptions.Add(uri, context.Server);
            }
            return ValueTask.FromResult(new EmptyResult());
        }
    );

The client is sending a subscribe request like this:

await mcpClient.SubscribeToResourceAsync(resourceUri);

I can see in the server logs that this request is received and processed:

info: ModelContextProtocol.Server.McpServer[570385771]
      Server (ResourceNotifications 1.0.0.0), Client (ResourceNotificationUpdateClient 1.0.0) method 'resources/subscribe' request handler called.
ModelContextProtocol.Server.McpServer: Information: Server (ResourceNotifications 1.0.0.0), Client (ResourceNotificationUpdateClient 1.0.0) method 'resources/subscribe' request handler completed.
info: ModelContextProtocol.Server.McpServer[1867955179]
      Server (ResourceNotifications 1.0.0.0), Client (ResourceNotificationUpdateClient 1.0.0) method 'resources/subscribe' request handler completed.

By setting break points in the server, I can see that the server is sending the notifications, but the client is not getting them.

To Reproduce

A project that reproduces the problem is in this GitHub repo/branch:

https://github.com/mikekistler/mcp-howto/tree/resource-notifications

Expected behavior

Resource notifications work.

Additional context

@stephentoub debugged this problem and reported the following:

Mike is stashing away the IMcpServer to send notifications to it in the background, but those notifications aren't getting through. The problem is that the SseWriter is getting disposed as part of the StreamableHttpServerTransport.HandlePostRequest disposing of the StreamableHttpPostTransport. The SseWriter then has logic in it that silently ignores all data written to it once disposed.

Discussion in the squad Teams channel ensued with the conclusion seeming to be:

In the default stateful mode, we could consider falling back to sending the message over the long-running GET SSE response if you try using the IMcpServer injected in a handler after the handler completes.

Metadata

Metadata

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions