use serde::{Deserialize, Serialize};
use schemars::JsonSchema;
#[derive(
Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, JsonSchema, arbitrary::Arbitrary,
)]
#[schemars(rename = "agent.ClientObjectiveaiMcpEntry")]
pub struct ClientObjectiveaiMcpEntry {
pub owner: String,
pub name: String,
pub version: String,
}
impl ClientObjectiveaiMcpEntry {
pub fn validate(&self) -> Result<(), String> {
if self.owner.is_empty() {
return Err("`owner` cannot be empty".into());
}
if self.name.is_empty() {
return Err("`name` cannot be empty".into());
}
if self.version.is_empty() {
return Err("`version` cannot be empty".into());
}
Ok(())
}
pub fn tool_name(&self) -> String {
materialize_tool_name(&self.owner, &self.name, &self.version)
}
}
pub fn materialize_tool_name(owner: &str, name: &str, version: &str) -> String {
format!("{owner}-{name}-{version}").replace('.', "-")
}
#[derive(
Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema, arbitrary::Arbitrary, Default,
)]
#[schemars(rename = "agent.ClientObjectiveaiMcp")]
pub struct ClientObjectiveaiMcp {
#[serde(default, skip_serializing_if = "Option::is_none")]
#[schemars(extend("omitempty" = true))]
pub objectiveai: Option<bool>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
#[schemars(extend("omitempty" = true))]
pub plugins: Vec<ClientObjectiveaiMcpEntry>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
#[schemars(extend("omitempty" = true))]
pub tools: Vec<ClientObjectiveaiMcpEntry>,
}
pub fn validate(this: &ClientObjectiveaiMcp) -> Result<(), String> {
for entry in &this.plugins {
entry.validate()?;
}
for entry in &this.tools {
entry.validate()?;
}
for (i, a) in this.plugins.iter().enumerate() {
for b in &this.plugins[i + 1..] {
if a == b {
return Err(format!(
"`client_objectiveai_mcp.plugins` contains duplicate entry: \"{}/{}@{}\"",
a.owner, a.name, a.version,
));
}
}
}
for (i, a) in this.tools.iter().enumerate() {
for b in &this.tools[i + 1..] {
if a == b {
return Err(format!(
"`client_objectiveai_mcp.tools` contains duplicate entry: \"{}/{}@{}\"",
a.owner, a.name, a.version,
));
}
}
}
Ok(())
}
pub fn prepare(mut this: ClientObjectiveaiMcp) -> Option<ClientObjectiveaiMcp> {
this.plugins.sort();
this.tools.sort();
if this.objectiveai.is_none() && this.plugins.is_empty() && this.tools.is_empty() {
None
} else {
Some(this)
}
}