use crate::cores::Cores;
pub async fn http_record(
cores: &Cores,
http_port: u16,
dashboard_enabled: bool,
enabled: bool,
) -> Option<String> {
if !enabled {
return None;
}
let mdns = cores.mdns.as_ref()?;
let hostname = hostname::get()
.ok()
.and_then(|os| os.into_string().ok())
.unwrap_or_else(|| "unknown".to_string());
let mut txt = std::collections::HashMap::new();
txt.insert("path".to_string(), "/".to_string());
txt.insert("version".to_string(), env!("CARGO_PKG_VERSION").to_string());
txt.insert("api".to_string(), "v1".to_string());
txt.insert("dashboard".to_string(), dashboard_enabled.to_string());
if let Some(ref certmesh) = cores.certmesh {
let id = certmesh.local_identity().await;
koi_common::peer::stamp(
&mut txt,
certmesh.posture(),
id.as_ref().map(|i| i.ca_fingerprint.as_str()),
id.as_ref().map(|i| i.renewal.expires_at),
);
}
let payload = koi_mdns::protocol::RegisterPayload {
name: format!("Koi ({hostname})"),
service_type: "_http._tcp".to_string(),
port: http_port,
ip: None,
lease_secs: None,
txt,
};
match mdns.register(payload) {
Ok(result) => {
tracing::info!(
id = %result.id,
port = http_port,
"HTTP server announced via mDNS"
);
Some(result.id)
}
Err(e) => {
tracing::warn!(error = %e, "Failed to announce HTTP server via mDNS");
None
}
}
}
pub async fn mcp_record(
cores: &Cores,
hostname: &str,
http_port: u16,
dns_zone: &str,
enabled: bool,
) -> Option<String> {
if !enabled {
return None;
}
if let Some(ref dns) = cores.dns {
let name = mcp_dns_name(hostname, dns_zone);
dns.core()
.add_txt(&name, "transport=streamable-http;path=/v1/mcp");
tracing::debug!(name = %name, "published in-zone MCP TXT descriptor");
}
let mdns = cores.mdns.as_ref()?;
let mut txt = std::collections::HashMap::new();
txt.insert("transport".to_string(), "streamable-http".to_string());
txt.insert("path".to_string(), "/v1/mcp".to_string());
txt.insert("version".to_string(), env!("CARGO_PKG_VERSION").to_string());
txt.insert("name".to_string(), format!("Koi MCP ({hostname})"));
let payload = koi_mdns::protocol::RegisterPayload {
name: format!("Koi MCP ({hostname})"),
service_type: "_mcp._tcp".to_string(),
port: http_port,
ip: None,
lease_secs: None,
txt,
};
match mdns.register(payload) {
Ok(result) => {
tracing::info!(id = %result.id, port = http_port, "MCP endpoint announced via mDNS (_mcp._tcp)");
Some(result.id)
}
Err(e) => {
tracing::warn!(error = %e, "Failed to announce MCP endpoint via mDNS");
None
}
}
}
pub fn withdraw_mcp(cores: &Cores, hostname: &str, dns_zone: &str, mcp_id: Option<&str>) {
if let (Some(id), Some(mdns)) = (mcp_id, cores.mdns.as_ref()) {
if let Err(e) = mdns.unregister(id) {
tracing::debug!(error = %e, "failed to withdraw _mcp._tcp announce");
}
}
if let Some(ref dns) = cores.dns {
dns.core().remove_txt(&mcp_dns_name(hostname, dns_zone));
}
}
pub(crate) fn local_hostname() -> String {
hostname::get()
.ok()
.and_then(|os| os.into_string().ok())
.unwrap_or_else(|| "unknown".to_string())
}
fn mcp_dns_name(hostname: &str, zone: &str) -> String {
format!("_mcp.{hostname}.{zone}")
}