use serde_json::Value;
use std::collections::HashMap;
use std::time::{Duration, Instant};
use turbomcp_protocol::jsonrpc::JsonRpcRequest;
#[derive(Debug, Clone)]
pub struct McpRequest {
pub request: JsonRpcRequest,
pub metadata: HashMap<String, Value>,
pub timestamp: Instant,
}
impl McpRequest {
#[must_use]
pub fn new(request: JsonRpcRequest) -> Self {
Self {
request,
metadata: HashMap::new(),
timestamp: Instant::now(),
}
}
#[must_use]
pub fn with_metadata(request: JsonRpcRequest, metadata: HashMap<String, Value>) -> Self {
Self {
request,
metadata,
timestamp: Instant::now(),
}
}
#[must_use]
pub fn method(&self) -> &str {
&self.request.method
}
#[must_use]
pub fn params(&self) -> Option<&Value> {
self.request.params.as_ref()
}
#[must_use]
pub fn id(&self) -> &turbomcp_protocol::MessageId {
&self.request.id
}
pub fn insert_metadata(&mut self, key: impl Into<String>, value: Value) {
self.metadata.insert(key.into(), value);
}
#[must_use]
pub fn get_metadata(&self, key: &str) -> Option<&Value> {
self.metadata.get(key)
}
#[must_use]
pub fn has_metadata(&self, key: &str) -> bool {
self.metadata.contains_key(key)
}
#[must_use]
pub fn elapsed(&self) -> Duration {
self.timestamp.elapsed()
}
}
impl From<JsonRpcRequest> for McpRequest {
fn from(request: JsonRpcRequest) -> Self {
Self::new(request)
}
}
#[derive(Debug, Clone)]
pub struct McpResponse {
pub result: Option<Value>,
pub error: Option<turbomcp_protocol::Error>,
pub metadata: HashMap<String, Value>,
pub duration: Duration,
}
impl McpResponse {
#[must_use]
pub fn success(result: Value, duration: Duration) -> Self {
Self {
result: Some(result),
error: None,
metadata: HashMap::new(),
duration,
}
}
#[must_use]
pub fn error(error: turbomcp_protocol::Error, duration: Duration) -> Self {
Self {
result: None,
error: Some(error),
metadata: HashMap::new(),
duration,
}
}
#[must_use]
pub fn is_success(&self) -> bool {
self.error.is_none()
}
#[must_use]
pub fn is_error(&self) -> bool {
self.error.is_some()
}
pub fn insert_metadata(&mut self, key: impl Into<String>, value: Value) {
self.metadata.insert(key.into(), value);
}
#[must_use]
pub fn get_metadata(&self, key: &str) -> Option<&Value> {
self.metadata.get(key)
}
pub fn take_result(&mut self) -> Option<Value> {
self.result.take()
}
pub fn take_error(&mut self) -> Option<turbomcp_protocol::Error> {
self.error.take()
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
use turbomcp_protocol::MessageId;
use turbomcp_protocol::jsonrpc::JsonRpcVersion;
fn test_request() -> JsonRpcRequest {
JsonRpcRequest {
jsonrpc: JsonRpcVersion,
id: MessageId::from("test-1"),
method: "test/method".to_string(),
params: Some(json!({"key": "value"})),
}
}
#[test]
fn test_mcp_request_creation() {
let req = McpRequest::new(test_request());
assert_eq!(req.method(), "test/method");
assert_eq!(req.params(), Some(&json!({"key": "value"})));
assert!(req.metadata.is_empty());
}
#[test]
fn test_mcp_request_metadata() {
let mut req = McpRequest::new(test_request());
req.insert_metadata("user_id", json!("user123"));
assert!(req.has_metadata("user_id"));
assert_eq!(req.get_metadata("user_id"), Some(&json!("user123")));
assert!(!req.has_metadata("nonexistent"));
}
#[test]
fn test_mcp_response_success() {
let resp = McpResponse::success(json!({"result": "ok"}), Duration::from_millis(100));
assert!(resp.is_success());
assert!(!resp.is_error());
assert_eq!(resp.result, Some(json!({"result": "ok"})));
assert_eq!(resp.duration, Duration::from_millis(100));
}
#[test]
fn test_mcp_response_error() {
let err = turbomcp_protocol::Error::internal("Test error");
let resp = McpResponse::error(err, Duration::from_millis(50));
assert!(!resp.is_success());
assert!(resp.is_error());
assert!(resp.error.is_some());
}
}