rmcp 1.5.0

Rust SDK for Model Context Protocol
Documentation
use std::{any::Any, time::Duration};

use rmcp::task_manager::{
    OperationDescriptor, OperationMessage, OperationProcessor, OperationResultTransport,
};

struct DummyTransport {
    id: String,
    value: u32,
}

impl OperationResultTransport for DummyTransport {
    fn operation_id(&self) -> &String {
        &self.id
    }

    fn as_any(&self) -> &dyn Any {
        self
    }
}

#[tokio::test]
async fn executes_enqueued_future() {
    let mut processor = OperationProcessor::new();
    let descriptor = OperationDescriptor::new("op1", "dummy");
    let future = Box::pin(async {
        tokio::time::sleep(Duration::from_millis(10)).await;
        Ok(Box::new(DummyTransport {
            id: "op1".to_string(),
            value: 42,
        }) as Box<dyn OperationResultTransport>)
    });

    processor
        .submit_operation(OperationMessage::new(descriptor, future))
        .expect("submit operation");

    tokio::time::sleep(Duration::from_millis(30)).await;
    let results = processor.peek_completed();
    assert_eq!(results.len(), 1);
    let payload = results[0]
        .result
        .as_ref()
        .unwrap()
        .as_any()
        .downcast_ref::<DummyTransport>()
        .unwrap();
    assert_eq!(payload.value, 42);
}

#[tokio::test]
async fn rejects_duplicate_operation_ids() {
    let mut processor = OperationProcessor::new();
    let descriptor = OperationDescriptor::new("dup", "dummy");
    let future = Box::pin(async {
        Ok(Box::new(DummyTransport {
            id: "dup".to_string(),
            value: 1,
        }) as Box<dyn OperationResultTransport>)
    });
    processor
        .submit_operation(OperationMessage::new(descriptor, future))
        .expect("first submit");

    let descriptor_dup = OperationDescriptor::new("dup", "dummy");
    let future_dup = Box::pin(async {
        Ok(Box::new(DummyTransport {
            id: "dup".to_string(),
            value: 2,
        }) as Box<dyn OperationResultTransport>)
    });

    let err = processor
        .submit_operation(OperationMessage::new(descriptor_dup, future_dup))
        .expect_err("duplicate should fail");
    assert!(format!("{err}").contains("already running"));
}