/// Resource content and result wrappers mirroring fastmcp/resources/base.py.
///|
/// The payload of a resource content item: inline text or raw bytes.
pub(all) enum ContentPayload {
Text(String)
Blob(Bytes)
} derive(Debug, Eq)
///|
/// A single resource content item with optional MIME type and metadata.
pub(all) struct ResourceContent {
content : ContentPayload
mime_type : String?
meta : Map[String, Json]?
} derive(Debug, Eq)
///|
/// Create a resource content item, defaulting the MIME type by payload:
/// `text/plain` for text, `application/octet-stream` for bytes.
pub fn ResourceContent::new(
content : ContentPayload,
mime_type? : String,
meta? : Map[String, Json],
) -> ResourceContent {
let mime_type = match content {
Text(_) => Some(mime_type.unwrap_or("text/plain"))
Blob(_) => Some(mime_type.unwrap_or("application/octet-stream"))
}
{ content, mime_type, meta, }
}
///|
/// Convert to the wire resource contents type; bytes are base64-encoded.
pub fn ResourceContent::to_mcp_resource_contents(
self : ResourceContent,
uri : String,
) -> @types.ResourceContents {
match self.content {
Text(text) => @types.Text(uri~, mime_type=self.mime_type, text~)
Blob(data) =>
@types.Blob(uri~, mime_type=self.mime_type, blob=@base64.encode(data))
}
}
///|
/// The canonical result of a resource read.
pub(all) struct ResourceResult {
contents : Array[ResourceContent]
meta : Map[String, Json]?
/// The client-input request when this read resolved to an input ask
/// (SEP-2322); `contents` is always empty in that case.
input_required : @types.InputRequiredResult?
} derive(Debug, Eq)
///|
/// Create a resource result from content items.
pub fn ResourceResult::new(
contents : Array[ResourceContent],
meta? : Map[String, Json],
) -> ResourceResult {
{ contents, meta, input_required: None, }
}
///|
/// Wrap a client-input ask (SEP-2322) as an ordinary resource result.
pub fn ResourceResult::input_required(
input_required : @types.InputRequiredResult,
) -> ResourceResult {
{ contents: [], meta: None, input_required: Some(input_required), }
}
///|
/// Whether this result carries a client-input ask (SEP-2322).
pub fn ResourceResult::is_input_required(self : ResourceResult) -> Bool {
self.input_required is Some(_)
}
///|
/// Convert to the wire read-resource result.
pub fn ResourceResult::to_mcp_result(
self : ResourceResult,
uri : String,
) -> @types.ReadResourceResult {
{
contents: self.contents.map(fn(item) { item.to_mcp_resource_contents(uri) }),
cache_control: None,
meta: self.meta,
}
}
///|
/// What a resource read function may return: text, bytes or a full result.
pub(all) enum RawResourceValue {
Text(String)
Blob(Bytes)
Ready(ResourceResult)
}
///|
/// Wrap a resource function's return value in a `ResourceResult`.
///
/// Shared by `Resource` and `ResourceTemplate` so both honour the MIME type
/// the component declares in listings: a component that advertises
/// `text/csv` must not serve `text/plain` on read.
pub fn convert_raw_to_resource_result(
raw_value : RawResourceValue,
mime_type? : String,
meta? : Map[String, Json],
) -> ResourceResult {
let public_meta = @component.public_result_meta(meta)
match raw_value {
Ready(result) => result
Text(text) =>
ResourceResult::new([
ResourceContent::new(Text(text), mime_type?, meta?=public_meta),
])
Blob(data) =>
ResourceResult::new([
ResourceContent::new(Blob(data), mime_type?, meta?=public_meta),
])
}
}
///|
pub extend ContentPayload with Debug::{to_repr}
///|
pub extend ContentPayload with Eq::{not_equal, equal}
///|
pub extend ResourceContent with Debug::{to_repr}
///|
pub extend ResourceContent with Eq::{not_equal, equal}
///|
pub extend ResourceResult with Debug::{to_repr}
///|
pub extend ResourceResult with Eq::{not_equal, equal}