use base64::Engine as _;
use base64::engine::general_purpose::STANDARD;
use std::borrow::Cow;
use std::fmt;
pub const SENTINEL_PREFIX: &str = "=?base64?";
pub const SENTINEL_SUFFIX: &str = "?=";
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum NameError {
NotBase64,
NotUtf8,
}
impl fmt::Display for NameError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::NotBase64 => f.write_str("Mcp-Name sentinel payload is not valid base64"),
Self::NotUtf8 => f.write_str("Mcp-Name sentinel payload is not valid UTF-8"),
}
}
}
impl std::error::Error for NameError {}
pub fn decode(raw: &str) -> Result<Cow<'_, str>, NameError> {
let Some(rest) = raw.strip_prefix(SENTINEL_PREFIX) else {
return Ok(Cow::Borrowed(raw));
};
let Some(payload) = rest.strip_suffix(SENTINEL_SUFFIX) else {
return Ok(Cow::Borrowed(raw));
};
let bytes = STANDARD.decode(payload).map_err(|_| NameError::NotBase64)?;
let decoded = String::from_utf8(bytes).map_err(|_| NameError::NotUtf8)?;
Ok(Cow::Owned(decoded))
}
#[must_use]
pub fn is_sentinel(raw: &str) -> bool {
raw.strip_prefix(SENTINEL_PREFIX)
.is_some_and(|rest| rest.ends_with(SENTINEL_SUFFIX))
}
#[must_use]
pub fn encode(value: &str) -> String {
format!(
"{SENTINEL_PREFIX}{}{SENTINEL_SUFFIX}",
STANDARD.encode(value.as_bytes())
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn plain_ascii_passes_through_borrowed() {
let decoded = decode("get_weather").expect("plain value decodes");
assert_eq!(decoded, "get_weather");
assert!(
matches!(decoded, Cow::Borrowed(_)),
"plain path must not allocate"
);
}
#[test]
fn decodes_the_specs_own_examples() {
assert_eq!(
decode("=?base64?SGVsbG8sIOS4lueVjA==?=").unwrap(),
"Hello, 世界"
);
assert_eq!(decode("=?base64?IHBhZGRlZCA=?=").unwrap(), " padded ");
assert_eq!(
decode("=?base64?bGluZTEKbGluZTI=?=").unwrap(),
"line1\nline2"
);
assert_eq!(
decode("=?base64?PT9iYXNlNjQ/bGl0ZXJhbD89?=").unwrap(),
"=?base64?literal?="
);
}
#[test]
fn uses_the_standard_alphabet_not_url_safe() {
let encoded = encode("=?base64?literal?=");
assert!(
encoded.contains('/'),
"expected standard-alphabet output: {encoded}"
);
assert_eq!(decode(&encoded).unwrap(), "=?base64?literal?=");
}
#[test]
fn resource_uris_survive_the_round_trip() {
let uri = "file:///projects/myapp/config.json";
assert_eq!(decode(uri).unwrap(), uri);
assert_eq!(decode(&encode(uri)).unwrap(), uri);
}
#[test]
fn empty_sentinel_payload_decodes_to_empty() {
assert_eq!(decode("=?base64??=").unwrap(), "");
}
#[test]
fn partial_markers_are_literals_not_errors() {
assert_eq!(decode("=?base64?SGVsbG8=").unwrap(), "=?base64?SGVsbG8=");
assert_eq!(decode("SGVsbG8=?=").unwrap(), "SGVsbG8=?=");
assert_eq!(decode("=?base64?=").unwrap(), "=?base64?=");
}
#[test]
fn markers_are_case_sensitive() {
assert_eq!(
decode("=?BASE64?SGVsbG8=?=").unwrap(),
"=?BASE64?SGVsbG8=?="
);
assert!(!is_sentinel("=?BASE64?SGVsbG8=?="));
}
#[test]
fn malformed_payloads_are_rejected_rather_than_guessed() {
assert_eq!(
decode("=?base64?not!valid!base64?=").unwrap_err(),
NameError::NotBase64
);
let bad_utf8 = format!(
"{SENTINEL_PREFIX}{}{SENTINEL_SUFFIX}",
STANDARD.encode([0xFF])
);
assert_eq!(decode(&bad_utf8).unwrap_err(), NameError::NotUtf8);
}
#[test]
fn is_sentinel_agrees_with_decode() {
for raw in [
"get_weather",
"=?base64?SGVsbG8=?=",
"=?base64?SGVsbG8=",
"=?base64??=",
] {
let sentinel = is_sentinel(raw);
let changed = !matches!(decode(raw), Ok(Cow::Borrowed(_)));
assert_eq!(sentinel, changed, "disagreement on {raw}");
}
}
#[test]
fn round_trips_arbitrary_unicode() {
for value in [
"",
"a",
"日本語",
"emoji 🦀 tool",
" spaced ",
"tab\there",
] {
assert_eq!(
decode(&encode(value)).unwrap(),
value,
"failed on {value:?}"
);
}
}
}