use serde::{Deserialize, Serialize};
use tatara_lisp::DeriveTataraDomain;
#[derive(DeriveTataraDomain, Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
#[serde(rename_all = "camelCase")]
#[tatara(keyword = "defmcp")]
pub struct McpToolSpec {
pub name: String,
#[serde(default)]
pub description: String,
#[serde(default)]
pub server: String,
#[serde(default)]
pub tool: String,
#[serde(default)]
pub input_schema: String,
#[serde(default)]
pub filetype: String,
#[serde(default)]
pub keybind: String,
#[serde(default)]
pub on_result: String,
#[serde(default)]
pub background: bool,
}
impl McpToolSpec {
#[must_use]
pub fn qualified_id(&self) -> String {
format!("{}.{}", self.server, self.tool)
}
#[must_use]
pub fn has_valid_on_result(&self) -> bool {
if self.on_result.is_empty() {
return true;
}
self.on_result.starts_with("action:")
|| self.on_result.starts_with("command:")
|| self.on_result.starts_with("workflow:")
}
pub const ON_RESULT_PREFIXES: &'static [&'static str] =
&["action:", "command:", "workflow:"];
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn qualified_id_renders_server_dot_tool() {
let s = McpToolSpec {
name: "x".into(),
server: "mado".into(),
tool: "clipboard_get".into(),
..Default::default()
};
assert_eq!(s.qualified_id(), "mado.clipboard_get");
}
#[test]
fn on_result_empty_is_valid_means_discard() {
let s = McpToolSpec {
name: "x".into(),
..Default::default()
};
assert!(s.has_valid_on_result());
assert!(s.on_result.is_empty());
}
#[test]
fn on_result_accepts_each_prefix_kind() {
for prefix in ["action:save", "command:buffer.write-all", "workflow:ship-rust"] {
let s = McpToolSpec {
name: "x".into(),
on_result: prefix.into(),
..Default::default()
};
assert!(s.has_valid_on_result(), "should accept {prefix:?}");
}
}
#[test]
fn on_result_rejects_unknown_prefix() {
for bad in ["notify:x", "inline:x", "lol", "just-text"] {
let s = McpToolSpec {
name: "x".into(),
on_result: bad.into(),
..Default::default()
};
assert!(!s.has_valid_on_result(), "should reject {bad:?}");
}
}
#[test]
fn on_result_prefixes_const_exposes_exactly_three() {
assert_eq!(
McpToolSpec::ON_RESULT_PREFIXES,
&["action:", "command:", "workflow:"],
);
}
}