feat: migrate JsonRpcMessage/Request/Response/Error/Notification from internal mcp crates to rmcp versions (#3564)
This commit is contained in:
@@ -4,8 +4,10 @@ use std::{
|
||||
};
|
||||
|
||||
use futures::{Future, Stream};
|
||||
use mcp_core::protocol::{JsonRpcError, JsonRpcMessage, JsonRpcResponse};
|
||||
use pin_project::pin_project;
|
||||
use rmcp::model::{
|
||||
ErrorData, JsonRpcError, JsonRpcMessage, JsonRpcResponse, JsonRpcVersion2_0, RequestId,
|
||||
};
|
||||
use router::McpRequest;
|
||||
use tokio::{
|
||||
io::{AsyncBufReadExt, AsyncRead, AsyncWrite, AsyncWriteExt, BufReader},
|
||||
@@ -151,14 +153,11 @@ where
|
||||
Ok(msg) => {
|
||||
match msg {
|
||||
JsonRpcMessage::Request(request) => {
|
||||
// Serialize request for logging
|
||||
let id = request.id;
|
||||
let request_json = serde_json::to_string(&request)
|
||||
.unwrap_or_else(|_| "Failed to serialize request".to_string());
|
||||
|
||||
tracing::info!(
|
||||
request_id = ?id,
|
||||
method = ?request.method,
|
||||
method = ?request.request.method,
|
||||
json = %request_json,
|
||||
"Received request"
|
||||
);
|
||||
@@ -184,16 +183,11 @@ where
|
||||
Err(e) => {
|
||||
let error_msg = e.into().to_string();
|
||||
tracing::error!(error = %error_msg, "Request processing failed");
|
||||
JsonRpcResponse {
|
||||
jsonrpc: "2.0".to_string(),
|
||||
id,
|
||||
result: None,
|
||||
error: Some(mcp_core::protocol::ErrorData {
|
||||
code: mcp_core::protocol::INTERNAL_ERROR,
|
||||
message: error_msg,
|
||||
data: None,
|
||||
}),
|
||||
}
|
||||
|
||||
// Return an error response instead of a regular response
|
||||
return Err(ServerError::Transport(TransportError::Protocol(
|
||||
error_msg,
|
||||
)));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -226,39 +220,38 @@ where
|
||||
}
|
||||
JsonRpcMessage::Response(_)
|
||||
| JsonRpcMessage::Notification(_)
|
||||
| JsonRpcMessage::Nil
|
||||
| JsonRpcMessage::BatchRequest(_)
|
||||
| JsonRpcMessage::BatchResponse(_)
|
||||
| JsonRpcMessage::Error(_) => {
|
||||
// Ignore responses, notifications and nil messages for now
|
||||
// Ignore responses, notifications, batch messages and error messages for now
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
// Convert transport error to JSON-RPC error response
|
||||
let error = match e {
|
||||
TransportError::Json(_) | TransportError::InvalidMessage(_) => {
|
||||
mcp_core::protocol::ErrorData {
|
||||
code: mcp_core::protocol::PARSE_ERROR,
|
||||
message: e.to_string(),
|
||||
data: None,
|
||||
}
|
||||
}
|
||||
TransportError::Protocol(_) => mcp_core::protocol::ErrorData {
|
||||
code: mcp_core::protocol::INVALID_REQUEST,
|
||||
message: e.to_string(),
|
||||
let error_data = match e {
|
||||
TransportError::Json(_) | TransportError::InvalidMessage(_) => ErrorData {
|
||||
code: rmcp::model::ErrorCode::PARSE_ERROR,
|
||||
message: e.to_string().into(),
|
||||
data: None,
|
||||
},
|
||||
_ => mcp_core::protocol::ErrorData {
|
||||
code: mcp_core::protocol::INTERNAL_ERROR,
|
||||
message: e.to_string(),
|
||||
TransportError::Protocol(_) => ErrorData {
|
||||
code: rmcp::model::ErrorCode::INVALID_REQUEST,
|
||||
message: e.to_string().into(),
|
||||
data: None,
|
||||
},
|
||||
_ => ErrorData {
|
||||
code: rmcp::model::ErrorCode::INTERNAL_ERROR,
|
||||
message: e.to_string().into(),
|
||||
data: None,
|
||||
},
|
||||
};
|
||||
|
||||
let error_response = JsonRpcMessage::Error(JsonRpcError {
|
||||
jsonrpc: "2.0".to_string(),
|
||||
id: None,
|
||||
error,
|
||||
jsonrpc: JsonRpcVersion2_0,
|
||||
id: RequestId::Number(0), // Use a default ID for transport errors
|
||||
error: error_data,
|
||||
});
|
||||
|
||||
if let Err(e) = transport.write_message(error_response).await {
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
use anyhow::Result;
|
||||
use mcp_core::handler::{PromptError, ResourceError};
|
||||
use mcp_core::protocol::JsonRpcMessage;
|
||||
use mcp_core::tool::ToolAnnotations;
|
||||
use mcp_core::{handler::ToolError, protocol::ServerCapabilities, tool::Tool};
|
||||
use mcp_server::router::{CapabilitiesBuilder, RouterService};
|
||||
use mcp_server::{ByteTransport, Router, Server};
|
||||
use rmcp::model::{Content, Prompt, PromptArgument, RawResource, Resource};
|
||||
use rmcp::model::{Content, JsonRpcMessage, Prompt, PromptArgument, RawResource, Resource};
|
||||
use serde_json::Value;
|
||||
use std::{future::Future, pin::Pin, sync::Arc};
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
@@ -5,17 +5,18 @@ use std::{
|
||||
};
|
||||
|
||||
type PromptFuture = Pin<Box<dyn Future<Output = Result<String, PromptError>> + Send + 'static>>;
|
||||
|
||||
use mcp_core::{
|
||||
handler::{PromptError, ResourceError, ToolError},
|
||||
protocol::{
|
||||
CallToolResult, GetPromptResult, Implementation, InitializeResult, JsonRpcMessage,
|
||||
JsonRpcRequest, JsonRpcResponse, ListPromptsResult, ListResourcesResult, ListToolsResult,
|
||||
PromptsCapability, ReadResourceResult, ResourcesCapability, ServerCapabilities,
|
||||
ToolsCapability,
|
||||
CallToolResult, GetPromptResult, Implementation, InitializeResult, ListPromptsResult,
|
||||
ListResourcesResult, ListToolsResult, PromptsCapability, ReadResourceResult,
|
||||
ResourcesCapability, ServerCapabilities, ToolsCapability,
|
||||
},
|
||||
};
|
||||
use rmcp::model::{Content, Prompt, PromptMessage, PromptMessageRole, Resource, ResourceContents};
|
||||
use rmcp::model::{
|
||||
Content, JsonRpcMessage, JsonRpcRequest, JsonRpcResponse, JsonRpcVersion2_0, Prompt,
|
||||
PromptMessage, PromptMessageRole, RequestId, Resource, ResourceContents,
|
||||
};
|
||||
use serde_json::Value;
|
||||
use tokio::sync::mpsc;
|
||||
use tower_service::Service;
|
||||
@@ -101,15 +102,32 @@ pub trait Router: Send + Sync + 'static {
|
||||
fn get_prompt(&self, prompt_name: &str) -> PromptFuture;
|
||||
|
||||
// Helper method to create base response
|
||||
fn create_response(&self, id: Option<u64>) -> JsonRpcResponse {
|
||||
fn create_response(&self, id: RequestId) -> JsonRpcResponse {
|
||||
JsonRpcResponse {
|
||||
jsonrpc: "2.0".to_string(),
|
||||
jsonrpc: JsonRpcVersion2_0,
|
||||
id,
|
||||
result: None,
|
||||
error: None,
|
||||
result: serde_json::Map::new(),
|
||||
}
|
||||
}
|
||||
|
||||
// Helper method to set result on response
|
||||
fn set_result<T: serde::Serialize>(
|
||||
&self,
|
||||
response: &mut JsonRpcResponse,
|
||||
result: T,
|
||||
) -> Result<(), RouterError> {
|
||||
let value = serde_json::to_value(result)
|
||||
.map_err(|e| RouterError::Internal(format!("JSON serialization error: {}", e)))?;
|
||||
|
||||
if let Some(obj) = value.as_object() {
|
||||
response.result = obj.clone();
|
||||
} else {
|
||||
return Err(RouterError::Internal("Result must be a JSON object".into()));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_initialize(
|
||||
&self,
|
||||
req: JsonRpcRequest,
|
||||
@@ -126,11 +144,7 @@ pub trait Router: Send + Sync + 'static {
|
||||
};
|
||||
|
||||
let mut response = self.create_response(req.id);
|
||||
response.result =
|
||||
Some(serde_json::to_value(result).map_err(|e| {
|
||||
RouterError::Internal(format!("JSON serialization error: {}", e))
|
||||
})?);
|
||||
|
||||
self.set_result(&mut response, result)?;
|
||||
Ok(response)
|
||||
}
|
||||
}
|
||||
@@ -147,11 +161,7 @@ pub trait Router: Send + Sync + 'static {
|
||||
next_cursor: None,
|
||||
};
|
||||
let mut response = self.create_response(req.id);
|
||||
response.result =
|
||||
Some(serde_json::to_value(result).map_err(|e| {
|
||||
RouterError::Internal(format!("JSON serialization error: {}", e))
|
||||
})?);
|
||||
|
||||
self.set_result(&mut response, result)?;
|
||||
Ok(response)
|
||||
}
|
||||
}
|
||||
@@ -162,9 +172,7 @@ pub trait Router: Send + Sync + 'static {
|
||||
notifier: mpsc::Sender<JsonRpcMessage>,
|
||||
) -> impl Future<Output = Result<JsonRpcResponse, RouterError>> + Send {
|
||||
async move {
|
||||
let params = req
|
||||
.params
|
||||
.ok_or_else(|| RouterError::InvalidParams("Missing parameters".into()))?;
|
||||
let params = &req.request.params;
|
||||
|
||||
let name = params
|
||||
.get("name")
|
||||
@@ -185,11 +193,7 @@ pub trait Router: Send + Sync + 'static {
|
||||
};
|
||||
|
||||
let mut response = self.create_response(req.id);
|
||||
response.result =
|
||||
Some(serde_json::to_value(result).map_err(|e| {
|
||||
RouterError::Internal(format!("JSON serialization error: {}", e))
|
||||
})?);
|
||||
|
||||
self.set_result(&mut response, result)?;
|
||||
Ok(response)
|
||||
}
|
||||
}
|
||||
@@ -206,11 +210,7 @@ pub trait Router: Send + Sync + 'static {
|
||||
next_cursor: None,
|
||||
};
|
||||
let mut response = self.create_response(req.id);
|
||||
response.result =
|
||||
Some(serde_json::to_value(result).map_err(|e| {
|
||||
RouterError::Internal(format!("JSON serialization error: {}", e))
|
||||
})?);
|
||||
|
||||
self.set_result(&mut response, result)?;
|
||||
Ok(response)
|
||||
}
|
||||
}
|
||||
@@ -220,9 +220,7 @@ pub trait Router: Send + Sync + 'static {
|
||||
req: JsonRpcRequest,
|
||||
) -> impl Future<Output = Result<JsonRpcResponse, RouterError>> + Send {
|
||||
async move {
|
||||
let params = req
|
||||
.params
|
||||
.ok_or_else(|| RouterError::InvalidParams("Missing parameters".into()))?;
|
||||
let params = &req.request.params;
|
||||
|
||||
let uri = params
|
||||
.get("uri")
|
||||
@@ -240,11 +238,7 @@ pub trait Router: Send + Sync + 'static {
|
||||
};
|
||||
|
||||
let mut response = self.create_response(req.id);
|
||||
response.result =
|
||||
Some(serde_json::to_value(result).map_err(|e| {
|
||||
RouterError::Internal(format!("JSON serialization error: {}", e))
|
||||
})?);
|
||||
|
||||
self.set_result(&mut response, result)?;
|
||||
Ok(response)
|
||||
}
|
||||
}
|
||||
@@ -259,11 +253,7 @@ pub trait Router: Send + Sync + 'static {
|
||||
let result = ListPromptsResult { prompts };
|
||||
|
||||
let mut response = self.create_response(req.id);
|
||||
response.result =
|
||||
Some(serde_json::to_value(result).map_err(|e| {
|
||||
RouterError::Internal(format!("JSON serialization error: {}", e))
|
||||
})?);
|
||||
|
||||
self.set_result(&mut response, result)?;
|
||||
Ok(response)
|
||||
}
|
||||
}
|
||||
@@ -274,9 +264,7 @@ pub trait Router: Send + Sync + 'static {
|
||||
) -> impl Future<Output = Result<JsonRpcResponse, RouterError>> + Send {
|
||||
async move {
|
||||
// Validate and extract parameters
|
||||
let params = req
|
||||
.params
|
||||
.ok_or_else(|| RouterError::InvalidParams("Missing parameters".into()))?;
|
||||
let params = &req.request.params;
|
||||
|
||||
// Extract "name" field
|
||||
let prompt_name = params
|
||||
@@ -381,13 +369,11 @@ pub trait Router: Send + Sync + 'static {
|
||||
|
||||
// Build the final response
|
||||
let mut response = self.create_response(req.id);
|
||||
response.result = Some(
|
||||
serde_json::to_value(GetPromptResult {
|
||||
description: Some(description_filled),
|
||||
messages,
|
||||
})
|
||||
.map_err(|e| RouterError::Internal(format!("JSON serialization error: {}", e)))?,
|
||||
);
|
||||
let result = GetPromptResult {
|
||||
description: Some(description_filled),
|
||||
messages,
|
||||
};
|
||||
self.set_result(&mut response, result)?;
|
||||
Ok(response)
|
||||
}
|
||||
}
|
||||
@@ -416,7 +402,7 @@ where
|
||||
let this = self.0.clone();
|
||||
|
||||
Box::pin(async move {
|
||||
let result = match req.request.method.as_str() {
|
||||
let result = match req.request.request.method.as_str() {
|
||||
"initialize" => this.handle_initialize(req.request).await,
|
||||
"tools/list" => this.handle_tools_list(req.request).await,
|
||||
"tools/call" => this.handle_tools_call(req.request, req.notifier).await,
|
||||
@@ -425,9 +411,9 @@ where
|
||||
"prompts/list" => this.handle_prompts_list(req.request).await,
|
||||
"prompts/get" => this.handle_prompts_get(req.request).await,
|
||||
_ => {
|
||||
let mut response = this.create_response(req.request.id);
|
||||
response.error = Some(RouterError::MethodNotFound(req.request.method).into());
|
||||
Ok(response)
|
||||
return Err(
|
||||
RouterError::MethodNotFound(req.request.request.method.clone()).into(),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user