use car_engine::{McpToolInfo, ToolEntry, ToolPermission, ToolSource};
use car_ir::ToolSchema;
use serde_json::json;
pub fn canonical_tool_name(slug: &str, tool: &str) -> String {
format!("mcp_{slug}_{tool}")
}
pub fn slugify(name: &str) -> String {
let mut s = String::new();
let mut last_us = false;
for ch in name.chars() {
if ch.is_ascii_alphanumeric() {
s.push(ch.to_ascii_lowercase());
last_us = false;
} else if !last_us {
s.push('_');
last_us = true;
}
}
let trimmed = s.trim_matches('_');
if trimmed.is_empty() {
"connector".to_string()
} else {
trimmed.to_string()
}
}
pub fn tool_entry(slug: &str, tool: &McpToolInfo) -> ToolEntry {
let schema = ToolSchema {
name: canonical_tool_name(slug, &tool.name),
description: tool.description.clone().unwrap_or_default(),
parameters: tool
.input_schema
.clone()
.unwrap_or_else(|| json!({"type": "object"})),
returns: None,
idempotent: false,
cache_ttl_secs: None,
rate_limit: None,
};
ToolEntry::new(schema)
.with_source(ToolSource::Mcp {
server_name: slug.to_string(),
})
.with_permission(ToolPermission::Allow)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn slugify_collapses_and_lowercases() {
assert_eq!(slugify("GitHub Issues!"), "github_issues");
assert_eq!(slugify(" spaced out "), "spaced_out");
assert_eq!(slugify("Acme/Linear"), "acme_linear");
assert_eq!(slugify("***"), "connector");
assert_eq!(slugify("Notion"), "notion");
}
#[test]
fn canonical_name_matches_engine_scheme() {
assert_eq!(
canonical_tool_name("github", "create_issue"),
"mcp_github_create_issue"
);
}
#[test]
fn tool_entry_carries_schema_and_source() {
let info = McpToolInfo {
name: "create_issue".into(),
description: Some("Open an issue".into()),
input_schema: Some(json!({"type": "object", "properties": {"title": {"type": "string"}}})),
};
let entry = tool_entry("github", &info);
assert_eq!(entry.schema.name, "mcp_github_create_issue");
assert_eq!(entry.schema.description, "Open an issue");
assert_eq!(entry.schema.parameters["properties"]["title"]["type"], "string");
assert_eq!(
entry.source,
ToolSource::Mcp {
server_name: "github".into()
}
);
}
}