use serde::Serialize;
use turbomcp_core::{McpError, McpResult};
use turbomcp_protocol::neutral;
pub trait IntoCallToolResult {
fn into_call_tool_result(self) -> McpResult<neutral::CallToolResult>;
}
#[derive(Clone, Copy, Debug)]
pub struct Json<T>(pub T);
impl IntoCallToolResult for neutral::CallToolResult {
fn into_call_tool_result(self) -> McpResult<neutral::CallToolResult> {
Ok(self)
}
}
impl IntoCallToolResult for String {
fn into_call_tool_result(self) -> McpResult<neutral::CallToolResult> {
Ok(neutral::CallToolResult::text(self))
}
}
impl IntoCallToolResult for &str {
fn into_call_tool_result(self) -> McpResult<neutral::CallToolResult> {
Ok(neutral::CallToolResult::text(self))
}
}
impl IntoCallToolResult for () {
fn into_call_tool_result(self) -> McpResult<neutral::CallToolResult> {
Ok(neutral::CallToolResult::default())
}
}
macro_rules! scalar_tool_result {
($($t:ty),* $(,)?) => {$(
impl IntoCallToolResult for $t {
fn into_call_tool_result(self) -> McpResult<neutral::CallToolResult> {
Ok(neutral::CallToolResult::text(self.to_string()))
}
}
)*};
}
scalar_tool_result!(
i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64, bool,
);
#[derive(Clone, Debug)]
pub struct Image {
pub data: String,
pub mime_type: String,
}
#[derive(Clone, Debug)]
pub struct Audio {
pub data: String,
pub mime_type: String,
}
impl IntoCallToolResult for Image {
fn into_call_tool_result(self) -> McpResult<neutral::CallToolResult> {
Ok(neutral::CallToolResult::new(vec![neutral::Content::image(
self.data,
self.mime_type,
)]))
}
}
impl IntoCallToolResult for Audio {
fn into_call_tool_result(self) -> McpResult<neutral::CallToolResult> {
Ok(neutral::CallToolResult::new(vec![neutral::Content::audio(
self.data,
self.mime_type,
)]))
}
}
impl<T: Serialize> IntoCallToolResult for Json<T> {
fn into_call_tool_result(self) -> McpResult<neutral::CallToolResult> {
let value = serde_json::to_value(&self.0)
.map_err(|e| McpError::internal(format!("serializing Json tool result: {e}")))?;
let mirror = value.to_string();
let mut result = neutral::CallToolResult::text(mirror);
result.structured_content = Some(value);
Ok(result)
}
}
impl<T> IntoCallToolResult for McpResult<T>
where
T: IntoCallToolResult,
{
fn into_call_tool_result(self) -> McpResult<neutral::CallToolResult> {
match self {
Ok(v) => v.into_call_tool_result(),
Err(e @ (McpError::InputRequired | McpError::MissingRequiredCapability(_))) => Err(e),
Err(e) => Ok(neutral::CallToolResult::error(e.to_string())),
}
}
}
pub trait IntoReadResourceResult {
fn into_read_resource_result(self, uri: &str) -> McpResult<neutral::ReadResourceResult>;
}
impl IntoReadResourceResult for neutral::ReadResourceResult {
fn into_read_resource_result(self, _uri: &str) -> McpResult<neutral::ReadResourceResult> {
Ok(self)
}
}
impl IntoReadResourceResult for String {
fn into_read_resource_result(self, uri: &str) -> McpResult<neutral::ReadResourceResult> {
Ok(neutral::ReadResourceResult::text(uri, self))
}
}
impl IntoReadResourceResult for &str {
fn into_read_resource_result(self, uri: &str) -> McpResult<neutral::ReadResourceResult> {
Ok(neutral::ReadResourceResult::text(uri, self))
}
}
impl<T> IntoReadResourceResult for McpResult<T>
where
T: IntoReadResourceResult,
{
fn into_read_resource_result(self, uri: &str) -> McpResult<neutral::ReadResourceResult> {
self.and_then(|v| v.into_read_resource_result(uri))
}
}
pub trait IntoGetPromptResult {
fn into_get_prompt_result(self) -> McpResult<neutral::GetPromptResult>;
}
impl IntoGetPromptResult for neutral::GetPromptResult {
fn into_get_prompt_result(self) -> McpResult<neutral::GetPromptResult> {
Ok(self)
}
}
impl IntoGetPromptResult for String {
fn into_get_prompt_result(self) -> McpResult<neutral::GetPromptResult> {
Ok(neutral::GetPromptResult::new(vec![
neutral::PromptMessage::user_text(self),
]))
}
}
impl IntoGetPromptResult for &str {
fn into_get_prompt_result(self) -> McpResult<neutral::GetPromptResult> {
Ok(neutral::GetPromptResult::new(vec![
neutral::PromptMessage::user_text(self),
]))
}
}
impl<T> IntoGetPromptResult for McpResult<T>
where
T: IntoGetPromptResult,
{
fn into_get_prompt_result(self) -> McpResult<neutral::GetPromptResult> {
self.and_then(IntoGetPromptResult::into_get_prompt_result)
}
}