You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
So now that we have the client working pretty well with the latest streamable http spec, i'm starting to work on upgrading our servers to support the server side of said spec.
I believe we may have a design issue, or maybe (hopefully) i'm missing something. The current design of the client->transport ->->-> a server works fine because typically a client app would have a single instance of a client (per server to connect to). That coupling becomes an issue on the server side, though. A server needs to allow more than one client to connect to it, and then any given client needs to be able to have multiple connections open within its session.
I've been studying the official TS streamable server code and of course while the syntax will be vastly different, i think i have a handle on the direction we need to go to do it properly. Basically, the server needs to allow multiple transports to be added (vs just one like it is currently). Each connection from a client would create a new transport which would be added to the server for that session. The GETs (which are all just one direction, server->client) would sit in there and all general messages would get written to all of them. The POSTs would also add their own transports to that session's server, but they would be shorter lived and let the server write to just that one transport, identified by the incoming id of the POST request. The spec explicitly states a client can have mutliple connections open so while we don't necessarily have to match the exact approach of the TS implementation, we must do something at least remotely similar.
Have you given this area much thought and if so, what are the thoughts? If not, I may go ahead and work on a POC in my fork
Hi @stallent. Thanks for giving this some thought.
My mental model is that server transport will manage a pool of connections to one or more clients. The specific implementation of that transport will depend on which web framework you build on top of. But at a high-level, it should look similar to this Swift NIO example chat server, where you have a dictionary of channels by client ID.
Partially. I think my struggles with that approach is you now have to maintain a fully functioning HTTP Server in front of it. Is that something that is within the scope or purview of this framework? I have a hunch devs wanting to deploy Swift servers are gonna prefer to go with the Vapor/Hummingbird frameworks where they already have all the things needed for HTTP (auth, sessions, persistence, middleware blah blah blah). Our are all containerized Hummingbird servers deployed to various clouds and k8 clusters
@stallent Yeah, I think that's correct. Instead of pulling in Vapor or Hummingbird into this SDK, you'd install a hummingbird-mcp or vapor-mcp package, which would provide a transport and APIs to mount MCP servers at a particular route.
Correct. In fact, creating a mcp-hummingbird is exactly what i was going to do. But i think we would require some changes to the Server regardless, though. Either the server needs allow multiple transports, or we need to be able to inject some state into the server (the latter would be so we can have a server/transport per connection, but don't wanna re-init each server). Several ways to skin that cat, so to speak, but i believe changes in the server class will be required regardless.
Alright. I have something minimal to look at that supports the streamable server spec and hopefully spurs discussion.
I used the official TS server and transport code as an implementation guide so my code somewhat mimics that. Its worth noting that the TS client puts a lot more of the mcp types and knowledge in the transport vs being exclusively in the server. To mimic that for the moment i had to add some redundant json decoding in the transport. Figured i'd start with that vs making larger changes to the Server class.
Hi @stallent! Do you need any support completing this? I have some use cases for this so would love to help. Let me know what's left to do or any challenges I can look into!
Hello @rosecoder. Happy to you get something usable. We were somewhat waiting on feedback from Mattt before opening a PR since it requires some small architectural changes to his base to do it reasonably. I have been running off a variant of my fork for months and its working just fine, so if you want to work with me to polish up a HummingbirdMCP package based on my fork would be very happy to do so.
@stallent thanks for your work on this we are looking into building an Swift MCP Server and currently use Hummingbird for our APIs so this would be an ideal solution.
Thanks @stallent I was able to get a POC up and running on AWS Lambda and integrated in to MS Copilot. The main issue I hit which I think relates more to Lambda was with the use of consumeWithInboundCloseHandler which was working locally but crashing when run in Lambda:
This looks great, but the origin is now many commits ahead. @mattt, is there a chance we can merge the streaming changes before the forks diverge any further?
@ronaldmannak i can at least get my branch sync'd up and verified tomorrow. Further improvements are close to bubbling up to the top of my prio list anyway/
@stallent no rush, I've manually merged and synced the two and everything seems to be working. It would just be a bit easier if it was a single repo :) Thanks for the great work!
@ronaldmannak@sebsto fwiw i sync'd up my fork of this repo just to ensure it was the latest and still worked. I also fixed a tiny issue in my hummingbird example where the latest mcp inspector from anthro complains if the server says it supports logging, but doesn't respond to the "logging/setLevel" method. Haven't looked into supporting that so for the moment just return nil for logging.
Activity
mattt commentedon May 9, 2025
Hi @stallent. Thanks for giving this some thought.
My mental model is that server transport will manage a pool of connections to one or more clients. The specific implementation of that transport will depend on which web framework you build on top of. But at a high-level, it should look similar to this Swift NIO example chat server, where you have a dictionary of channels by client ID.
Does that track for you?
stallent commentedon May 9, 2025
Partially. I think my struggles with that approach is you now have to maintain a fully functioning HTTP Server in front of it. Is that something that is within the scope or purview of this framework? I have a hunch devs wanting to deploy Swift servers are gonna prefer to go with the Vapor/Hummingbird frameworks where they already have all the things needed for HTTP (auth, sessions, persistence, middleware blah blah blah). Our are all containerized Hummingbird servers deployed to various clouds and k8 clusters
mattt commentedon May 9, 2025
@stallent Yeah, I think that's correct. Instead of pulling in Vapor or Hummingbird into this SDK, you'd install a
hummingbird-mcporvapor-mcppackage, which would provide a transport and APIs to mount MCP servers at a particular route.stallent commentedon May 9, 2025
Correct. In fact, creating a mcp-hummingbird is exactly what i was going to do. But i think we would require some changes to the Server regardless, though. Either the server needs allow multiple transports, or we need to be able to inject some state into the server (the latter would be so we can have a server/transport per connection, but don't wanna re-init each server). Several ways to skin that cat, so to speak, but i believe changes in the server class will be required regardless.
stallent commentedon May 9, 2025
i'll proceed with a POC on a fork for us to look at and assess. Won't open a PR or anything.
mattt commentedon May 9, 2025
@stallent Sounds good! Excited to see what you come up with.
stallent commentedon May 11, 2025
making solid progress. should have POS POC up tomorrow at some point
stallent commentedon May 12, 2025
Alright. I have something minimal to look at that supports the streamable server spec and hopefully spurs discussion.
I used the official TS server and transport code as an implementation guide so my code somewhat mimics that. Its worth noting that the TS client puts a lot more of the mcp types and knowledge in the transport vs being exclusively in the server. To mimic that for the moment i had to add some redundant json decoding in the transport. Figured i'd start with that vs making larger changes to the Server class.
The changes to the swift-sdk are in the streamable_server branch of my fork here:
https://github.com/stallent/swift-sdk/tree/streamable_server
with the specific changes being this commit:
stallent@164ec48
The Hummingbird part isn't yet in a re-usable package for and at the moment, but otherwise should illustrate full usage.
https://github.com/stallent/hummingbird-mcp
rosecoder commentedon Jul 4, 2025
Hi @stallent! Do you need any support completing this? I have some use cases for this so would love to help. Let me know what's left to do or any challenges I can look into!
stallent commentedon Jul 5, 2025
Hello @rosecoder. Happy to you get something usable. We were somewhat waiting on feedback from Mattt before opening a PR since it requires some small architectural changes to his base to do it reasonably. I have been running off a variant of my fork for months and its working just fine, so if you want to work with me to polish up a HummingbirdMCP package based on my fork would be very happy to do so.
johnmorrell commentedon Jul 24, 2025
@stallent thanks for your work on this we are looking into building an Swift MCP Server and currently use Hummingbird for our APIs so this would be an ideal solution.
stallent commentedon Jul 25, 2025
@johnmorrell happy to help as needed.
johnmorrell commentedon Jul 25, 2025
Thanks @stallent I was able to get a POC up and running on AWS Lambda and integrated in to MS Copilot. The main issue I hit which I think relates more to Lambda was with the use of
consumeWithInboundCloseHandlerwhich was working locally but crashing when run in Lambda:https://github.com/stallent/hummingbird-mcp/blob/eedf2f19056c9fbe643a5d342df3e66258723d55/Sources/App/StreamableMCPController.swift#L89
I was able to get it running replacing this with
withTaskCancellationHandlerbut not sure on the implications of this.ronaldmannak commentedon Sep 16, 2025
This looks great, but the origin is now many commits ahead. @mattt, is there a chance we can merge the streaming changes before the forks diverge any further?
stallent commentedon Sep 16, 2025
@ronaldmannak i can at least get my branch sync'd up and verified tomorrow. Further improvements are close to bubbling up to the top of my prio list anyway/
ronaldmannak commentedon Sep 16, 2025
@stallent no rush, I've manually merged and synced the two and everything seems to be working. It would just be a bit easier if it was a single repo :) Thanks for the great work!
sebsto commentedon Oct 5, 2025
@mattt what is missing to merge @stallent work in the project ? Let us know if there are any blocker that we can help with
stallent commentedon Oct 10, 2025
@ronaldmannak @sebsto fwiw i sync'd up my fork of this repo just to ensure it was the latest and still worked. I also fixed a tiny issue in my hummingbird example where the latest mcp inspector from anthro complains if the server says it supports logging, but doesn't respond to the "logging/setLevel" method. Haven't looked into supporting that so for the moment just return nil for logging.
ronaldmannak commentedon Oct 10, 2025
@stallent that's great. Thanks!
DePasqualeOrg commentedon Jan 4, 2026
I've implemented this functionality in my PR #175. I'd love to hear your feedback if you're able to test it.
stallent commentedon Feb 25, 2026
Closing as we have a path now!