Skip to content

Commit 9a771fb

Browse files
authored
refactor: Transport trait and worker transport, and streamable http client with those new features. (#167)
* refactor: a transport trait and streamable http client * test: test with js streamable http server * refactor: separate sse stream connection * fix(test): streamable http client test with js * fix(test): wait longer time for js server startup
1 parent 01eedb7 commit 9a771fb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+2761
-1315
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,15 +157,16 @@ jobs:
157157
- uses: actions/checkout@v3
158158

159159
- name: Install Rust
160-
uses: dtolnay/rust-toolchain@stable
160+
uses: dtolnay/rust-toolchain@nightly
161161

162162
- uses: Swatinem/rust-cache@v2
163163

164164
- name: Generate documentation
165165
run: |
166-
cargo doc --no-deps -p rmcp -p rmcp-macros
166+
cargo +nightly doc --no-deps -p rmcp -p rmcp-macros --all-features
167167
env:
168-
RUSTDOCFLAGS: -Dwarnings
168+
RUSTDOCFLAGS: --cfg docsrs -Dwarnings
169+
RUSTFLAGS: --cfg docsrs
169170

170171
release:
171172
name: Release crates

README.md

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,18 +45,24 @@ use tokio::io::{stdin, stdout};
4545
let transport = (stdin(), stdout());
4646
```
4747

48-
The transport type must implemented [`IntoTransport`](crate::transport::IntoTransport) trait, which allow split into a sink and a stream.
48+
#### Transport
49+
The transport type must implemented [`Transport`] trait, which allow it send message concurrently and receive message sequentially.
50+
There are 3 pairs of standard transport types:
4951

50-
For client, the sink item is [`ClientJsonRpcMessage`](crate::model::ClientJsonRpcMessage) and stream item is [`ServerJsonRpcMessage`](crate::model::ServerJsonRpcMessage)
52+
| transport | client | server |
53+
|:-: |:-: |:-: |
54+
| std IO | [`child_process::TokioChildProcess`] | [`io::stdio`] |
55+
| streamable http | [`streamable_http_client::StreamableHttpClientTransport`] | [`streamable_http_server::session::create_session`] |
56+
| sse | [`sse_client::SseClientTransport`] | [`sse_server::SseServer`] |
5157

52-
For server, the sink item is [`ServerJsonRpcMessage`](crate::model::ServerJsonRpcMessage) and stream item is [`ClientJsonRpcMessage`](crate::model::ClientJsonRpcMessage)
58+
#### [IntoTransport](`IntoTransport`) trait
59+
[`IntoTransport`] is a helper trait that implicitly convert a type into a transport type.
5360

54-
##### These types is automatically implemented [`IntoTransport`](crate::transport::IntoTransport) trait
55-
56-
1. The types that already implement both [`Sink`](futures::Sink) and [`Stream`](futures::Stream) trait.
57-
2. A tuple of sink `Tx` and stream `Rx`: `(Tx, Rx)`.
58-
3. The type that implement both [`tokio::io::AsyncRead`] and [`tokio::io::AsyncWrite`] trait.
59-
4. A tuple of [`tokio::io::AsyncRead`] `R `and [`tokio::io::AsyncWrite`] `W`: `(R, W)`.
61+
These types is automatically implemented [`IntoTransport`] trait
62+
1. A type that already implement both [`futures::Sink`] and [`futures::Stream`] trait, or a tuple `(Tx, Rx)` where `Tx` is [`futures::Sink`] and `Rx` is [`futures::Stream`].
63+
2. A type that implement both [`tokio::io::AsyncRead`] and [`tokio::io::AsyncWrite`] trait. or a tuple `(R, W)` where `R` is [`tokio::io::AsyncRead`] and `W` is [`tokio::io::AsyncWrite`].
64+
3. A type that implement [Worker](`worker::Worker`) trait.
65+
4. A type that implement [`Transport`] trait.
6066

6167
For example, you can see how we build a transport through TCP stream or http upgrade so easily. [examples](examples/README.md)
6268
</details>
@@ -194,13 +200,15 @@ See [examples](examples/README.md)
194200
- `macros`: macros default
195201
- `schemars`: implement `JsonSchema` for all model structs
196202

197-
### Transports
203+
#### Transports
198204

199205
- `transport-io`: Server stdio transport
200206
- `transport-sse-server`: Server SSE transport
201207
- `transport-child-process`: Client stdio transport
202-
- `transport-sse`: Client sse transport
208+
- `transport-sse-client`: Client sse transport
203209
- `transport-streamable-http-server` streamable http server transport
210+
- `transport-streamable-client-server` streamable http server transport
211+
204212

205213
## Related Resources
206214

crates/rmcp/Cargo.toml

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ documentation = "https://docs.rs/rmcp"
1111

1212
[package.metadata.docs.rs]
1313
all-features = true
14+
rustdoc-args = ["--cfg", "docsrs"]
1415

1516
[dependencies]
1617
serde = { version = "1.0", features = ["derive", "rc"] }
@@ -38,7 +39,7 @@ reqwest = { version = "0.12", default-features = false, features = [
3839
"json",
3940
"stream",
4041
], optional = true }
41-
sse-stream = { version = "0.1.3", optional = true }
42+
sse-stream = { version = "0.1.4", optional = true }
4243
url = { version = "2.4", optional = true }
4344

4445
# For tower compatibility
@@ -62,9 +63,26 @@ default = ["base64", "macros", "server"]
6263
client = []
6364
server = ["transport-async-rw", "dep:schemars"]
6465
macros = ["dep:rmcp-macros", "dep:paste"]
65-
__transport-sse = ["dep:reqwest", "dep:sse-stream", "dep:url"]
66+
67+
# reqwest http client
68+
reqwest = ["dep:reqwest"]
69+
70+
# SSE client
71+
client-side-sse = ["dep:sse-stream"]
72+
73+
__transport-sse = ["reqwest", "client-side-sse", "dep:url", "transport-worker"]
74+
75+
transport-worker = ["dep:tokio-stream"]
76+
6677
transport-sse = ["__transport-sse", "reqwest?/rustls-tls"]
6778
transport-sse-tls-no-provider = ["__transport-sse", "reqwest?/rustls-tls-no-provider"]
79+
80+
# Streamable HTTP client
81+
__transport-streamable-http-client = ["reqwest", "client-side-sse", "transport-worker", "dep:url"]
82+
transport-streamable-http-client = ["__transport-streamable-http-client", "reqwest?/rustls-tls"]
83+
transport-streamable-http-client-tls-no-provider = ["__transport-streamable-http-client", "reqwest?/rustls-tls-no-provider"]
84+
85+
6886
transport-async-rw = ["tokio/io-util", "tokio-util/codec"]
6987
transport-io = ["transport-async-rw", "tokio/io-std"]
7088
transport-child-process = ["transport-async-rw", "tokio/process"]
@@ -114,7 +132,7 @@ path = "tests/test_with_python.rs"
114132

115133
[[test]]
116134
name = "test_with_js"
117-
required-features = ["server", "client", "transport-sse-server", "transport-child-process", "transport-streamable-http-server"]
135+
required-features = ["server", "client", "transport-sse-server", "transport-child-process", "transport-streamable-http-server", "transport-streamable-http-client"]
118136
path = "tests/test_with_js.rs"
119137

120138
[[test]]

crates/rmcp/src/handler.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#[cfg(feature = "client")]
2+
#[cfg_attr(docsrs, doc(cfg(feature = "client")))]
23
pub mod client;
34
#[cfg(feature = "server")]
5+
#[cfg_attr(docsrs, doc(cfg(feature = "server")))]
46
pub mod server;

crates/rmcp/src/handler/server/tool.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,7 @@ impl<S> ToolBox<S> {
431431
}
432432

433433
#[cfg(feature = "macros")]
434+
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
434435
#[macro_export]
435436
macro_rules! tool_box {
436437
(@pin_add $callee: ident, $attr: expr, $f: expr) => {

crates/rmcp/src/lib.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![cfg_attr(docsrs, feature(doc_cfg))]
2+
#![cfg_attr(docsrs, allow(unused_attributes))]
13
//! The official Rust SDK for the Model Context Protocol (MCP).
24
//!
35
//! The MCP is a protocol that allows AI assistants to communicate with other
@@ -93,29 +95,40 @@ pub use error::Error;
9395
/// Basic data types in MCP specification
9496
pub mod model;
9597
#[cfg(any(feature = "client", feature = "server"))]
98+
#[cfg_attr(docsrs, doc(cfg(any(feature = "client", feature = "server"))))]
9699
pub mod service;
97100
#[cfg(feature = "client")]
101+
#[cfg_attr(docsrs, doc(cfg(feature = "client")))]
98102
pub use handler::client::ClientHandler;
99103
#[cfg(feature = "server")]
104+
#[cfg_attr(docsrs, doc(cfg(feature = "server")))]
100105
pub use handler::server::ServerHandler;
101106
#[cfg(any(feature = "client", feature = "server"))]
107+
#[cfg_attr(docsrs, doc(cfg(any(feature = "client", feature = "server"))))]
102108
pub use service::{Peer, Service, ServiceError, ServiceExt};
103109
#[cfg(feature = "client")]
110+
#[cfg_attr(docsrs, doc(cfg(feature = "client")))]
104111
pub use service::{RoleClient, serve_client};
105112
#[cfg(feature = "server")]
113+
#[cfg_attr(docsrs, doc(cfg(feature = "server")))]
106114
pub use service::{RoleServer, serve_server};
107115

108116
pub mod handler;
109117
pub mod transport;
110118

111119
// re-export
112120
#[cfg(all(feature = "macros", feature = "server"))]
121+
#[cfg_attr(docsrs, doc(cfg(all(feature = "macros", feature = "server"))))]
113122
pub use paste::paste;
114123
#[cfg(all(feature = "macros", feature = "server"))]
124+
#[cfg_attr(docsrs, doc(cfg(all(feature = "macros", feature = "server"))))]
115125
pub use rmcp_macros::tool;
116126
#[cfg(all(feature = "macros", feature = "server"))]
127+
#[cfg_attr(docsrs, doc(cfg(all(feature = "macros", feature = "server"))))]
117128
pub use schemars;
118129
#[cfg(feature = "macros")]
130+
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
119131
pub use serde;
120132
#[cfg(feature = "macros")]
133+
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
121134
pub use serde_json;

crates/rmcp/src/model.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pub fn object(value: serde_json::Value) -> JsonObject {
3636

3737
/// Use this macro just like [`serde_json::json!`]
3838
#[cfg(feature = "macros")]
39+
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
3940
#[macro_export]
4041
macro_rules! object {
4142
({$($tt:tt)*}) => {

0 commit comments

Comments
 (0)