feat: migrate JsonRpcMessage/Request/Response/Error/Notification from internal mcp crates to rmcp versions (#3564)
This commit is contained in:
@@ -1,8 +1,12 @@
|
||||
use mcp_core::protocol::{
|
||||
CallToolResult, GetPromptResult, Implementation, InitializeResult, JsonRpcError,
|
||||
JsonRpcMessage, JsonRpcNotification, JsonRpcRequest, JsonRpcResponse, ListPromptsResult,
|
||||
CallToolResult, GetPromptResult, Implementation, InitializeResult, ListPromptsResult,
|
||||
ListResourcesResult, ListToolsResult, ReadResourceResult, ServerCapabilities, METHOD_NOT_FOUND,
|
||||
};
|
||||
|
||||
use rmcp::model::{
|
||||
JsonRpcError, JsonRpcMessage, JsonRpcNotification, JsonRpcRequest, JsonRpcResponse,
|
||||
JsonRpcVersion2_0, Notification, NumberOrString, Request, RequestId,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::{json, Value};
|
||||
use std::sync::{
|
||||
@@ -112,7 +116,7 @@ where
|
||||
T: TransportHandle + Send + Sync + 'static,
|
||||
{
|
||||
service: Mutex<tower::timeout::Timeout<McpService<T>>>,
|
||||
next_id: AtomicU64,
|
||||
next_id_counter: AtomicU64, // Added for atomic ID generation
|
||||
server_capabilities: Option<ServerCapabilities>,
|
||||
server_info: Option<Implementation>,
|
||||
notification_subscribers: Arc<Mutex<Vec<mpsc::Sender<JsonRpcMessage>>>>,
|
||||
@@ -135,8 +139,14 @@ where
|
||||
Ok(message) => {
|
||||
tracing::info!("Received message: {:?}", message);
|
||||
match message {
|
||||
JsonRpcMessage::Response(JsonRpcResponse { id: Some(id), .. })
|
||||
| JsonRpcMessage::Error(JsonRpcError { id: Some(id), .. }) => {
|
||||
JsonRpcMessage::Response(JsonRpcResponse {
|
||||
id: NumberOrString::Number(id),
|
||||
..
|
||||
})
|
||||
| JsonRpcMessage::Error(JsonRpcError {
|
||||
id: NumberOrString::Number(id),
|
||||
..
|
||||
}) => {
|
||||
service_ptr.respond(&id.to_string(), Ok(message)).await;
|
||||
}
|
||||
_ => {
|
||||
@@ -158,7 +168,7 @@ where
|
||||
|
||||
Ok(Self {
|
||||
service: Mutex::new(middleware.layer(service)),
|
||||
next_id: AtomicU64::new(1),
|
||||
next_id_counter: AtomicU64::new(1),
|
||||
server_capabilities: None,
|
||||
server_info: None,
|
||||
notification_subscribers,
|
||||
@@ -172,7 +182,8 @@ where
|
||||
{
|
||||
let mut service = self.service.lock().await;
|
||||
service.ready().await.map_err(|_| Error::NotReady)?;
|
||||
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
|
||||
let id_num = self.next_id_counter.fetch_add(1, Ordering::SeqCst);
|
||||
let id = RequestId::Number(id_num as u32);
|
||||
|
||||
let mut params = params.clone();
|
||||
params["_meta"] = json!({
|
||||
@@ -180,10 +191,13 @@ where
|
||||
});
|
||||
|
||||
let request = JsonRpcMessage::Request(JsonRpcRequest {
|
||||
jsonrpc: "2.0".to_string(),
|
||||
id: Some(id),
|
||||
method: method.to_string(),
|
||||
params: Some(params),
|
||||
jsonrpc: JsonRpcVersion2_0,
|
||||
id,
|
||||
request: Request {
|
||||
method: method.to_string(),
|
||||
params: params.as_object().unwrap().clone(),
|
||||
extensions: Default::default(),
|
||||
},
|
||||
});
|
||||
|
||||
let response_msg = service
|
||||
@@ -201,35 +215,26 @@ where
|
||||
})?;
|
||||
|
||||
match response_msg {
|
||||
JsonRpcMessage::Response(JsonRpcResponse {
|
||||
id, result, error, ..
|
||||
}) => {
|
||||
// Verify id matches
|
||||
if id != Some(self.next_id.load(Ordering::SeqCst) - 1) {
|
||||
JsonRpcMessage::Response(JsonRpcResponse { id, result, .. }) => {
|
||||
// Verify id matches - convert current id to match expected format
|
||||
let expected_id = RequestId::Number((id_num) as u32);
|
||||
if id != expected_id {
|
||||
return Err(Error::UnexpectedResponse(
|
||||
"id mismatch for JsonRpcResponse".to_string(),
|
||||
));
|
||||
}
|
||||
if let Some(err) = error {
|
||||
Err(Error::RpcError {
|
||||
code: err.code,
|
||||
message: err.message,
|
||||
})
|
||||
} else if let Some(r) = result {
|
||||
Ok(serde_json::from_value(r)?)
|
||||
} else {
|
||||
Err(Error::UnexpectedResponse("missing result".to_string()))
|
||||
}
|
||||
Ok(serde_json::from_value(serde_json::to_value(result)?)?)
|
||||
}
|
||||
JsonRpcMessage::Error(JsonRpcError { id, error, .. }) => {
|
||||
if id != Some(self.next_id.load(Ordering::SeqCst) - 1) {
|
||||
let expected_id = RequestId::Number((id_num) as u32);
|
||||
if id != expected_id {
|
||||
return Err(Error::UnexpectedResponse(
|
||||
"id mismatch for JsonRpcError".to_string(),
|
||||
));
|
||||
}
|
||||
Err(Error::RpcError {
|
||||
code: error.code,
|
||||
message: error.message,
|
||||
code: error.code.0, // Extract the i32 from ErrorCode
|
||||
message: error.message.to_string(), // Convert Cow to String
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
@@ -247,9 +252,12 @@ where
|
||||
service.ready().await.map_err(|_| Error::NotReady)?;
|
||||
|
||||
let notification = JsonRpcMessage::Notification(JsonRpcNotification {
|
||||
jsonrpc: "2.0".to_string(),
|
||||
method: method.to_string(),
|
||||
params: Some(params.clone()),
|
||||
jsonrpc: JsonRpcVersion2_0,
|
||||
notification: Notification {
|
||||
method: method.to_string(),
|
||||
params: params.as_object().unwrap().clone(),
|
||||
extensions: Default::default(),
|
||||
},
|
||||
});
|
||||
|
||||
service
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use futures::future::BoxFuture;
|
||||
use mcp_core::protocol::{JsonRpcMessage, JsonRpcRequest};
|
||||
use rmcp::model::{JsonRpcMessage, JsonRpcRequest};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::task::{Context, Poll};
|
||||
@@ -50,8 +50,8 @@ where
|
||||
let pending_requests = self.pending_requests.clone();
|
||||
|
||||
Box::pin(async move {
|
||||
match request {
|
||||
JsonRpcMessage::Request(JsonRpcRequest { id: Some(id), .. }) => {
|
||||
match &request {
|
||||
JsonRpcMessage::Request(JsonRpcRequest { id, .. }) => {
|
||||
// Create a channel to receive the response
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
pending_requests.insert(id.to_string(), sender).await;
|
||||
@@ -59,15 +59,17 @@ where
|
||||
transport.send(request).await?;
|
||||
receiver.await.map_err(|_| Error::ChannelClosed)?
|
||||
}
|
||||
JsonRpcMessage::Request(_) => {
|
||||
// Handle notifications without waiting for a response
|
||||
transport.send(request).await?;
|
||||
Ok(JsonRpcMessage::Nil)
|
||||
}
|
||||
JsonRpcMessage::Notification(_) => {
|
||||
// Handle notifications without waiting for a response
|
||||
transport.send(request).await?;
|
||||
Ok(JsonRpcMessage::Nil)
|
||||
// Return a dummy response for notifications
|
||||
let dummy_response: JsonRpcMessage =
|
||||
JsonRpcMessage::Response(rmcp::model::JsonRpcResponse {
|
||||
jsonrpc: rmcp::model::JsonRpcVersion2_0,
|
||||
id: rmcp::model::RequestId::Number(0),
|
||||
result: serde_json::Map::new(),
|
||||
});
|
||||
Ok(dummy_response)
|
||||
}
|
||||
_ => Err(Error::UnsupportedMessage),
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use async_trait::async_trait;
|
||||
use mcp_core::protocol::JsonRpcMessage;
|
||||
use rmcp::model::JsonRpcMessage;
|
||||
use thiserror::Error;
|
||||
use tokio::sync::{mpsc, oneshot};
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ use crate::transport::Error;
|
||||
use async_trait::async_trait;
|
||||
use eventsource_client::{Client, SSE};
|
||||
use futures::TryStreamExt;
|
||||
use mcp_core::protocol::JsonRpcMessage;
|
||||
use reqwest::Client as HttpClient;
|
||||
use rmcp::model::JsonRpcMessage;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::{mpsc, Mutex, RwLock};
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::sync::Arc;
|
||||
use tokio::process::{Child, ChildStderr, ChildStdin, ChildStdout, Command};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use mcp_core::protocol::JsonRpcMessage;
|
||||
use rmcp::model::JsonRpcMessage;
|
||||
use tokio::io::{AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader};
|
||||
use tokio::sync::{mpsc, Mutex};
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ use crate::transport::Error;
|
||||
use async_trait::async_trait;
|
||||
use eventsource_client::{Client, SSE};
|
||||
use futures::TryStreamExt;
|
||||
use mcp_core::protocol::{JsonRpcMessage, JsonRpcRequest};
|
||||
use reqwest::Client as HttpClient;
|
||||
use rmcp::model::{JsonRpcMessage, JsonRpcRequest, NumberOrString::Number};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::{mpsc, Mutex, RwLock};
|
||||
@@ -89,7 +89,7 @@ impl StreamableHttpActor {
|
||||
|
||||
let expects_response = matches!(
|
||||
parsed_message,
|
||||
JsonRpcMessage::Request(JsonRpcRequest { id: Some(_), .. })
|
||||
JsonRpcMessage::Request(JsonRpcRequest { id: Number(_), .. })
|
||||
);
|
||||
|
||||
// Try to send the request
|
||||
|
||||
Reference in New Issue
Block a user