use async_trait::async_trait;
use rmcp::model::{CallToolResult, Tool};
#[async_trait]
pub trait McpToolExtension: Send + Sync + 'static {
fn tools(&self) -> Vec<Tool>;
async fn execute(
&self,
tool_name: &str,
arguments: serde_json::Value,
tenant_id: &str,
) -> Option<Result<CallToolResult, String>>;
}
pub struct NoOpMcpExtension;
#[async_trait]
impl McpToolExtension for NoOpMcpExtension {
fn tools(&self) -> Vec<Tool> {
vec![]
}
async fn execute(
&self,
_tool_name: &str,
_arguments: serde_json::Value,
_tenant_id: &str,
) -> Option<Result<CallToolResult, String>> {
None
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_noop_extension_returns_empty_tools() {
let ext = NoOpMcpExtension;
assert!(ext.tools().is_empty(), "NoOp should provide no tools");
}
#[tokio::test]
async fn test_noop_extension_returns_none() {
let ext = NoOpMcpExtension;
let result = ext.execute("any_tool", serde_json::json!({}), "tenant_1").await;
assert!(result.is_none(), "NoOp should not handle any tool");
}
}