-
Notifications
You must be signed in to change notification settings - Fork 252
Add actix-web support #294
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
Add actix-web support #294
Conversation
- Add actix-web as an optional web framework alongside Axum - Refactor SSE server into modular structure with common types - Create actix_web implementation with identical API to Axum - Add comprehensive unit and integration tests for both implementations - Make actix-web the default when enabled (Axum still available as AxumSseServer) - Add working actix-web example (counter_sse_actix.rs) - Fix calculator test model to use #[tool_handler] macro - Verified 100% protocol compatibility with JavaScript and Python MCP clients The implementation maintains full backwards compatibility - when only the axum feature is enabled, the original Axum implementation is used.
The LocalSessionManager in streamable-http-server uses WorkerTransport, which requires the transport-worker feature. This was working accidentally in examples because transport-sse-server also includes transport-worker. Without this fix, using transport-streamable-http-server independently (without transport-sse-server) would fail to compile with unresolved import errors for WorkerTransport.
4db400e
to
a0b4487
Compare
Testing the HTTP streamable implNode:
Python: N/A Testing the SSE implNode:
Python:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds optional actix-web support alongside the existing Axum implementation by refactoring SSE and streamable HTTP transports into a shared structure, re-exporting framework-specific types behind convenience aliases, and updating examples and tests to cover both frameworks.
- Introduce actix-web-based implementations for SSE (
ActixSseServer
) and streamable HTTP (ActixStreamableHttpService
) while preserving the Axum paths. - Refactor
StreamableHttpServerConfig
out of the tower module into a common location and update re-exports intransport.rs
. - Extend examples (
counter_sse_actix.rs
,counter_streamable_http_actix.rs
) and test suites (test_with_python.rs
,test_with_js.rs
,test_sse_server.rs
) to exercise both Axum and actix-web flows.
Reviewed Changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 1 comment.
Show a summary per file
File | Description |
---|---|
examples/servers/src/counter_streamable_http_actix.rs | New example: streamable HTTP server using actix-web |
examples/servers/src/counter_sse_actix.rs | New example: SSE server using actix-web |
examples/servers/Cargo.toml | Enable actix-web optional dependencies and example registration |
crates/rmcp/tests/test_with_python.rs | Split Python-client test into common logic and framework variants |
crates/rmcp/tests/test_with_js.rs | Split JS-client test into common logic and add Axum/actix variants |
crates/rmcp/src/transport/streamable_http_server/tower.rs | Removed local config type; import shared StreamableHttpServerConfig |
crates/rmcp/src/transport/streamable_http_server/actix_impl.rs | New actix-web implementation for streamable HTTP service |
crates/rmcp/src/transport/streamable_http_server.rs | Add shared config, re-export convenience and explicit types |
crates/rmcp/src/transport/sse_server/mod.rs | Define module structure and convenience alias for SseServer |
crates/rmcp/src/transport/sse_server/common.rs | Extract SseServerConfig , SessionId , default keep-alive |
crates/rmcp/src/transport/sse_server/axum_impl.rs | Refactor axum SSE implementation to use shared common types |
crates/rmcp/src/transport/sse_server/actix_impl.rs | Add new actix-web SSE implementation |
crates/rmcp/src/transport/common/http_header.rs | Add HEADER_X_ACCEL_BUFFERING constant |
crates/rmcp/src/transport.rs | Update docs and re-exports to cover both Axum and actix-web |
crates/rmcp/Cargo.toml | Enable actix-web and async-stream dependencies and features |
Comments suppressed due to low confidence (2)
crates/rmcp/tests/test_with_js.rs:102
- This Axum JS client test does not invoke
init_js_tests().await
, so the environment and dependencies (e.g. npm install) might not be set up before the test runs. Consider calling the common initializer at the start of the test.
async fn test_with_js_streamable_http_client_axum() -> anyhow::Result<()> {
crates/rmcp/src/transport/streamable_http_server/actix_impl.rs:1
- [nitpick] This actix-web streamable HTTP implementation is nearly 500 lines long. Splitting route handlers (
handle_get
,handle_post
,handle_delete
) into smaller modules or files could improve readability and ease future maintenance.
use std::sync::Arc;
required-features = ["actix-web"] | ||
|
||
[features] | ||
actix-web = ["dep:actix-web", "dep:actix-rt", "rmcp/actix-web"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The entry "rmcp/actix-web" should be prefixed with "dep:" (i.e., "dep:rmcp/actix-web") so that the example’s rmcp dependency feature is correctly enabled.
actix-web = ["dep:actix-web", "dep:actix-rt", "rmcp/actix-web"] | |
actix-web = ["dep:actix-web", "dep:actix-rt", "dep:rmcp/actix-web"] |
Copilot uses AI. Check for mistakes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The entry "rmcp/actix-web" should be prefixed with "dep:" (i.e., "dep:rmcp/actix-web") so that the example’s rmcp dependency feature is correctly enabled.
rmcp/actix-web
is not a dependency. actix-web
is a feature of rmcp
. IMHO the suggestion is invalid.
- Implement ActixStreamableHttpService with full feature parity to Axum implementation - Support GET (SSE streams), POST (requests), DELETE (session cleanup) endpoints - Add comprehensive logging matching SSE implementation - Use X-Accel-Buffering header constant for consistency - Create working example server (counter_streamable_http_actix.rs) - Refactor tower.rs to import StreamableHttpServerConfig from parent module - Add HEADER_X_ACCEL_BUFFERING constant to common http_header module - Update streamable_client.js to accept URL as command line argument - Configure example to bind to 127.0.0.1 for IPv4 compatibility The actix-web implementation provides identical functionality to the Axum version while following actix-web patterns and conventions.
- Export framework-specific types with explicit names (AxumSseServer, ActixSseServer, etc.) - Add comprehensive module documentation explaining the type export strategy - Update all tests to use explicit type names with proper feature gates - Remove unused TransportReceiver type aliases to fix warnings - Ensure feature gates are ordered with framework feature last This design provides both explicit control when both frameworks are enabled and maintains backward compatibility with existing code.
- Use #[actix_web::test] instead of #[tokio::test] for actix-web tests - Add NormalizePath middleware to actix-web SSE server for consistent path handling
Only define the constant when actix-web feature is enabled to avoid dead code warning
The JavaScript streamable server is hardcoded to use port 8002, which was conflicting with our actix-web test. Changed actix-web test to use port 8004.
Reverted STREAMABLE_HTTP_JS_BIND_ADDRESS back to port 8002 to match the hardcoded port in streamable_server.js. Our actix-web test uses port 8004 to avoid conflicts.
The feature definition in examples/servers/Cargo.toml should use 'dep:rmcp/actix-web' to correctly enable the rmcp dependency feature.
…ort types - Remove type prefixes (AxumSseServer, ActixSseServer, etc.) - Organize implementations in framework-specific submodules (axum, actix_web) - Each submodule exports types with consistent names (SseServer, StreamableHttpService) - Update all imports to use new module paths - Maintain backward compatibility with convenience aliases at module roots This provides a cleaner API with better module organization and makes it easier to add new framework implementations in the future.
When running The error message:
This error is expected and not caused by changes in this branch. Here's why:
This is a timing issue where the cleanup happens after the server is terminated. It's not a |
- Document actix-web as an alternative web framework in README files - Add feature flag documentation explaining axum (default) vs actix-web - Include examples showing both framework usage patterns - Document precedence behavior when both features are enabled - Add explanatory comments to actix-web example files - Note runtime differences (#[actix_web::main] vs #[tokio::main])
IMHO everything checks out and this PR is ready for review. 🚀 |
Wooohoooo that CI fail is brutal. I'm on it 👍 |
Don't mind commit message ci, we will merge all commit into one when merge the pr. As for clippy and format, you can use |
And I also want to disscuss that should we maintain actix-web service in rmcp crate? If every web framework add their implementation in rmcp crate, it would be a challenge to maintain all of them. Will it be a good idea to seperate them to other crates? We can also add support like grpc and ws transport in this way. |
At some point, I wanted to use a trait for both the Axum and the actix_web implementations. But there were too dissimilar, mainly because each framework has it's own way to define routes/handlers. And I felt it was too early. Maybe a third leg would help designing the needed abstractions/traits. Maybe we don't need abstractions at all and the Still, a few things to consider:
|
Apply Rust formatting standards to ensure consistent code style across the codebase.
@4t145 all done. |
@JMLX42 It would be great if you are willing to maintain a repo to support actix-web for rcmp, and we can list the ecosystem here in rmcp. It's very hard to make a single piece of code compatible with all major web frameworks. After all they don't even depends on a same basic http type lib. It will be much better if there is some adapter to accept tower http service as other framwork's route, and the core work of it is the convertion bewteen So would you like maintain a crate, maybe named |
IMHO that's most of the work here: routing to the service. I'll double check the code, but if that's all there is (and the unavoidable framework specific boilerplate), it's good enough for quite some time.
@4t145 OK so new plan:
I'll do it this afternoon. |
First version: https://gitlab.com/lx-industries/rmcp-actix-web Still working on the CI/release system. |
First release: https://crates.io/crates/rmcp-actix-web I'll close this PR and open another one just to update the doc to add a link to the new crate. |
The implementation maintains full backwards compatibility - when only the axum feature is enabled, the original Axum implementation is used.
To Do
Motivation and Context
Add actix_web support to maximize the user base.
How Has This Been Tested?
Using the Python/JS test clients + unit tests mimicking the Axum impl.
Breaking Changes
None
Types of changes
Checklist
Additional context
Axum is still the default impl. There is no breaking change. The
actix-web
impl must be enabled and default features disabled in order to use the actix-web impl.