Skip to content

Commit 5cf8af8

Browse files
author
=
committed
Meta support extensions
1 parent ab3f5e7 commit 5cf8af8

File tree

10 files changed

+42
-20
lines changed

10 files changed

+42
-20
lines changed

crates/rmcp/src/model.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,12 +191,24 @@ impl<'de> Deserialize<'de> for NumberOrString {
191191
}
192192

193193
pub type RequestId = NumberOrString;
194-
pub type ProgressToken = NumberOrString;
195194

196195
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
196+
#[serde(transparent)]
197+
pub struct ProgressToken(pub NumberOrString);
198+
199+
200+
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
197201
#[serde(rename_all = "camelCase")]
198202
pub struct RequestMeta {
199-
pub progress_token: ProgressToken,
203+
pub progress_token: Option<ProgressToken>,
204+
#[serde(flatten)]
205+
pub ext: JsonObject
206+
}
207+
208+
impl RequestMeta {
209+
pub fn is_empty(&self) -> bool {
210+
self.progress_token.is_none() && self.ext.is_empty()
211+
}
200212
}
201213

202214
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
@@ -841,8 +853,8 @@ const_string!(CallToolRequestMethod = "tools/call");
841853
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
842854
#[serde(rename_all = "camelCase")]
843855
pub struct CallToolRequestParam {
844-
#[serde(skip_serializing_if = "Option::is_none")]
845-
pub _meta: Option<RequestMeta>,
856+
#[serde(skip_serializing_if = "RequestMeta::is_empty", default)]
857+
pub _meta: RequestMeta,
846858
pub name: Cow<'static, str>,
847859
#[serde(skip_serializing_if = "Option::is_none")]
848860
pub arguments: Option<JsonObject>,

crates/rmcp/src/model/meta.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,34 @@
11
use super::{ClientRequest, RequestMeta, ServerRequest};
22

33
pub trait WithMeta<M> {
4-
fn set_meta(&mut self, meta: Option<M>);
4+
fn get_meta_mut(&mut self) -> Option<&mut M>;
55
fn get_meta(&self) -> Option<&M>;
66
}
77

88
impl WithMeta<RequestMeta> for ClientRequest {
9-
fn set_meta(&mut self, meta: Option<RequestMeta>) {
9+
fn get_meta_mut(&mut self) -> Option<&mut RequestMeta> {
1010
#[allow(clippy::single_match)]
1111
match self {
12-
ClientRequest::CallToolRequest(req) => {
13-
req.params._meta = meta;
14-
}
15-
_ => {}
12+
ClientRequest::CallToolRequest(req) => Some(&mut req.params._meta),
13+
_ => None,
1614
}
1715
}
1816

1917
fn get_meta(&self) -> Option<&RequestMeta> {
2018
#[allow(clippy::single_match)]
2119
match self {
22-
ClientRequest::CallToolRequest(req) => req.params._meta.as_ref(),
20+
ClientRequest::CallToolRequest(req) => Some(&req.params._meta),
2321
_ => None,
2422
}
2523
}
2624
}
2725

2826
impl WithMeta<RequestMeta> for ServerRequest {
29-
fn set_meta(&mut self, _meta: Option<RequestMeta>) {}
30-
3127
fn get_meta(&self) -> Option<&RequestMeta> {
3228
None
3329
}
30+
31+
fn get_meta_mut(&mut self) -> Option<&mut RequestMeta> {
32+
None
33+
}
3434
}

crates/rmcp/src/service.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ use crate::{
66
model::{
77
CancelledNotification, CancelledNotificationParam, JsonRpcBatchRequestItem,
88
JsonRpcBatchResponseItem, JsonRpcError, JsonRpcMessage, JsonRpcNotification,
9-
JsonRpcRequest, JsonRpcResponse, ProgressToken, RequestId, RequestMeta, WithMeta,
9+
JsonRpcRequest, JsonRpcResponse, NumberOrString, ProgressToken, RequestId, RequestMeta,
10+
WithMeta,
1011
},
1112
transport::IntoTransport,
1213
};
@@ -220,8 +221,10 @@ impl RequestIdProvider for AtomicU32Provider {
220221
}
221222

222223
impl ProgressTokenProvider for AtomicU32Provider {
223-
fn next_progress_token(&self) -> RequestId {
224-
RequestId::Number(self.id.fetch_add(1, std::sync::atomic::Ordering::SeqCst))
224+
fn next_progress_token(&self) -> ProgressToken {
225+
ProgressToken(NumberOrString::Number(
226+
self.id.fetch_add(1, std::sync::atomic::Ordering::SeqCst),
227+
))
225228
}
226229
}
227230

@@ -379,9 +382,9 @@ impl<R: ServiceRole> Peer<R> {
379382
) -> Result<RequestHandle<R>, ServiceError> {
380383
let id = self.request_id_provider.next_request_id();
381384
let progress_token = self.progress_token_provider.next_progress_token();
382-
request.set_meta(Some(RequestMeta {
383-
progress_token: progress_token.clone(),
384-
}));
385+
if let Some(meta) = request.get_meta_mut() {
386+
meta.progress_token = Some(progress_token.clone());
387+
};
385388
let (responder, receiver) = tokio::sync::oneshot::channel();
386389
self.tx
387390
.send(PeerSinkMessage::Request {

crates/rmcp/src/transport/streamable_http/session.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ impl Session {
6161
if self.request_router.contains_key(&request_id) {
6262
return Err(SessionError::DuplicatedRequestId(request_id.clone()));
6363
};
64-
let progress_token = request.get_meta().map(|meta| meta.progress_token.clone());
64+
let progress_token = request.get_meta().and_then(|meta| meta.progress_token.clone());
6565
let (tx, rx) = tokio::sync::mpsc::channel(Self::REQUEST_WISE_CHANNEL_SIZE);
6666
self.send_to_service(ClientJsonRpcMessage::Request(JsonRpcRequest {
6767
request,

examples/clients/src/collection.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ async fn main() -> Result<()> {
3939
.call_tool(CallToolRequestParam {
4040
name: "git_status".into(),
4141
arguments: serde_json::json!({ "repo_path": "." }).as_object().cloned(),
42+
_meta: Default::default(),
4243
})
4344
.await?;
4445
}

examples/clients/src/everything_stdio.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ async fn main() -> Result<()> {
4141
.call_tool(CallToolRequestParam {
4242
name: "echo".into(),
4343
arguments: Some(object!({ "message": "hi from rmcp" })),
44+
_meta: Default::default(),
4445
})
4546
.await?;
4647
tracing::info!("Tool result for echo: {tool_result:#?}");
@@ -50,6 +51,7 @@ async fn main() -> Result<()> {
5051
.call_tool(CallToolRequestParam {
5152
name: "longRunningOperation".into(),
5253
arguments: Some(object!({ "duration": 3, "steps": 1 })),
54+
_meta: Default::default(),
5355
})
5456
.await?;
5557
tracing::info!("Tool result for longRunningOperation: {tool_result:#?}");

examples/clients/src/sse.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ async fn main() -> Result<()> {
4141
.call_tool(CallToolRequestParam {
4242
name: "increment".into(),
4343
arguments: serde_json::json!({}).as_object().cloned(),
44+
_meta: Default::default(),
4445
})
4546
.await?;
4647
tracing::info!("Tool result: {tool_result:#?}");

examples/clients/src/std_io.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ async fn main() -> Result<()> {
3939
.call_tool(CallToolRequestParam {
4040
name: "git_status".into(),
4141
arguments: serde_json::json!({ "repo_path": "." }).as_object().cloned(),
42+
_meta: Default::default(),
4243
})
4344
.await?;
4445
tracing::info!("Tool result: {tool_result:#?}");

examples/rig-integration/src/mcp_adaptor.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ impl RigTool for McpToolAdaptor {
4242
name: self.tool.name.clone(),
4343
arguments: serde_json::from_str(&args)
4444
.map_err(rig::tool::ToolError::JsonError)?,
45+
_meta: Default::default(),
4546
})
4647
.await
4748
.map_err(|e| rig::tool::ToolError::ToolCallError(Box::new(e)))?;

examples/transport/src/unix_socket.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ async fn client() -> anyhow::Result<()> {
7272
"a": 10,
7373
"b": 20
7474
})),
75+
_meta: Default::default()
7576
})
7677
.await?;
7778

0 commit comments

Comments
 (0)