pub const MCP_GATEWAY_TOOL_NAME: &str = "mcp";
pub const MCP_RESOURCE_TOOL_NAMES: &[&str] = &[
"list_mcp_resources",
"list_mcp_resource_templates",
"read_mcp_resource",
];
pub fn wildcard_matches(pattern: &str, text: &str) -> bool {
let p = pattern.as_bytes();
let t = text.as_bytes();
let (mut pi, mut ti) = (0usize, 0usize);
let (mut star, mut mark) = (None::<usize>, 0usize);
while ti < t.len() {
if pi < p.len() && p[pi] == b'*' {
star = Some(pi);
mark = ti;
pi += 1;
} else if pi < p.len() && p[pi] == t[ti] {
pi += 1;
ti += 1;
} else if let Some(s) = star {
pi = s + 1;
mark += 1;
ti = mark;
} else {
return false;
}
}
while pi < p.len() && p[pi] == b'*' {
pi += 1;
}
pi == p.len()
}
pub fn matches_any(entries: &[String], name: &str) -> bool {
entries.iter().any(|e| {
if e.contains('*') {
wildcard_matches(e, name)
} else {
e == name
}
})
}
pub fn is_mcp_tool_name(name: &str) -> bool {
name.starts_with("mcp__")
|| name == MCP_GATEWAY_TOOL_NAME
|| MCP_RESOURCE_TOOL_NAMES.contains(&name)
}
pub fn allowlist_filters_mcp(entries: &[String]) -> bool {
entries.is_empty() || entries.iter().any(|e| e.starts_with("mcp__"))
}
#[cfg(test)]
mod tests {
use super::*;
fn entries(list: &[&str]) -> Vec<String> {
list.iter().map(|s| s.to_string()).collect()
}
#[test]
fn wildcard_matches_arbitrary_segments() {
assert!(wildcard_matches("mcp__radius__*", "mcp__radius__get"));
assert!(wildcard_matches("mcp__radius__*", "mcp__radius__"));
assert!(wildcard_matches("*", "anything"));
assert!(wildcard_matches("*", ""));
assert!(wildcard_matches("read*", "read"));
assert!(wildcard_matches("*write*", "readwrite"));
assert!(wildcard_matches("a*b*c", "aXXbYYc"));
}
#[test]
fn wildcard_matches_is_anchored() {
assert!(!wildcard_matches("read", "reader"));
assert!(!wildcard_matches("mcp__radius__*", "mcp__other__get"));
assert!(!wildcard_matches("a*b*c", "aXbY"));
assert!(!wildcard_matches("abc", "abd"));
}
#[test]
fn matches_any_mixes_exact_and_pattern_entries() {
let list = entries(&["read", "mcp__radius__*"]);
assert!(matches_any(&list, "read"));
assert!(matches_any(&list, "mcp__radius__put"));
assert!(!matches_any(&list, "reader"));
assert!(!matches_any(&list, "mcp__other__put"));
assert!(!matches_any(&[], "read"));
}
#[test]
fn mcp_tool_names_are_recognized() {
assert!(is_mcp_tool_name("mcp"));
assert!(is_mcp_tool_name("mcp__docs__search"));
assert!(is_mcp_tool_name("read_mcp_resource"));
assert!(!is_mcp_tool_name("read"));
assert!(!is_mcp_tool_name("mcpx"));
}
#[test]
fn allowlist_filters_mcp_matches_pi() {
assert!(allowlist_filters_mcp(&[]));
assert!(allowlist_filters_mcp(&entries(&["read", "mcp__radius__*"])));
assert!(!allowlist_filters_mcp(&entries(&["read", "codemode"])));
}
}