///|
pub(all) enum IconTheme {
Light
Dark
} derive(Debug, Eq)
///|
pub fn IconTheme::to_string(self : IconTheme) -> String {
match self {
Light => "light"
Dark => "dark"
}
}
///|
pub impl ToJson for IconTheme with fn to_json(self : IconTheme) -> Json {
Json::string(self.to_string())
}
///|
/// Icon metadata for an MCP implementation.
pub struct Icon {
src : String
mime_type : String?
sizes : Array[String]
theme : IconTheme?
} derive(Debug, Eq)
///|
pub fn Icon::Icon(
src~ : String,
mime_type? : String,
sizes? : Array[String] = [],
theme? : IconTheme,
) -> Icon {
{ src, mime_type, sizes: sizes.copy(), theme }
}
///|
fn Icon::copy(self : Icon) -> Icon {
{ ..self, sizes: self.sizes.copy() }
}
///|
pub impl ToJson for Icon with fn to_json(self : Icon) -> Json {
let fields : Map[String, Json] = { "src": Json::string(self.src) }
fields.set_opt("mimeType", self.mime_type.map(Json::string))
if !self.sizes.is_empty() {
fields["sizes"] = self.sizes.to_json()
}
if self.theme is Some(theme) {
fields["theme"] = ToJson::to_json(theme)
}
Json::object(fields)
}
///|
pub impl @json.FromJson for Icon with fn from_json(
value : Json,
path : @json.JsonPath,
) -> Icon raise {
guard value is Object(fields) else {
raise JsonDecodeError((path, "expected an icon object"))
}
let src : String = match fields.get("src") {
Some(value) => @json.from_json(value, path=path.add_key("src"))
None => raise JsonDecodeError((path, "missing required field 'src'"))
}
let mime_type : String? = match fields.get("mimeType") {
Some(value) => Some(@json.from_json(value, path=path.add_key("mimeType")))
None => None
}
let sizes : Array[String] = match fields.get("sizes") {
Some(value) => @json.from_json(value, path=path.add_key("sizes"))
None => []
}
let theme : IconTheme? = match fields.get("theme") {
Some(String("light")) => Some(Light)
Some(String("dark")) => Some(Dark)
Some(_) =>
raise JsonDecodeError(
(path.add_key("theme"), "expected 'light' or 'dark'"),
)
None => None
}
Icon(src~, mime_type?, sizes~, theme?)
}
///|
/// MCP implementation metadata repeated in each stateless request or result.
pub struct Implementation {
name : String
title : String?
version : String
description : String?
icons : Array[Icon]
website_url : String?
} derive(Debug, Eq)
///|
pub fn Implementation::Implementation(
name~ : String,
version~ : String,
title? : String,
description? : String,
icons? : Array[Icon] = [],
website_url? : String,
) -> Implementation {
{
name,
title,
version,
description,
icons: icons.map(icon => icon.copy()),
website_url,
}
}
///|
fn Implementation::copy(self : Implementation) -> Implementation {
{ ..self, icons: self.icons.map(icon => icon.copy()) }
}
///|
pub impl ToJson for Implementation with fn to_json(self : Implementation) -> Json {
let fields : Map[String, Json] = {
"name": Json::string(self.name),
"version": Json::string(self.version),
}
fields.set_opt("title", self.title.map(Json::string))
fields.set_opt("description", self.description.map(Json::string))
if !self.icons.is_empty() {
fields["icons"] = self.icons
.map(fn(icon) { ToJson::to_json(icon) })
.to_json()
}
fields.set_opt("websiteUrl", self.website_url.map(Json::string))
Json::object(fields)
}
///|
pub impl @json.FromJson for Implementation with fn from_json(
value : Json,
path : @json.JsonPath,
) -> Implementation raise {
guard value is Object(fields) else {
raise JsonDecodeError((path, "expected an implementation object"))
}
let required_string = fn(key : String) -> String raise @json.JsonDecodeError {
match fields.get(key) {
Some(value) => @json.from_json(value, path=path.add_key(key))
None => raise JsonDecodeError((path, "missing required field '\{key}'"))
}
}
let optional_string = fn(
key : String,
) -> String? raise @json.JsonDecodeError {
match fields.get(key) {
Some(value) => Some(@json.from_json(value, path=path.add_key(key)))
None => None
}
}
let icons : Array[Icon] = match fields.get("icons") {
Some(value) => @json.from_json(value, path=path.add_key("icons"))
None => []
}
Implementation(
name=required_string("name"),
version=required_string("version"),
title?=optional_string("title"),
description?=optional_string("description"),
icons~,
website_url?=optional_string("websiteUrl"),
)
}