pub struct ToolName(/* private fields */);Expand description
Tool name identifier (newtype over String).
Represents the name of an MCP tool. Using a strong type ensures tool names are not
confused with other string values, and ToolName::new enforces the same baseline
shape as ServerId::new (see validate_path_segment and
first_disallowed_identifier_char, issue #433),
since generated tool names are ultimately used to derive output file names and are
rendered into LLM-facing text.
§Examples
use mcp_execution_core::ToolName;
let tool = ToolName::new("execute_code").unwrap();
assert_eq!(tool.as_str(), "execute_code");
assert!(ToolName::new("").is_err());Deserialize is routed through ToolName::new (via #[serde(try_from = "String")]),
so serde_json::from_str::<ToolName>(...) — or any struct with a ToolName field, such as
mcp_execution_introspector::ToolInfo — enforces the same invariant as calling new
directly; there is no separate, unvalidated deserialization path.
Implementations§
Source§impl ToolName
impl ToolName
Sourcepub fn new(name: impl Into<String>) -> Result<Self, ToolNameError>
pub fn new(name: impl Into<String>) -> Result<Self, ToolNameError>
Creates a new tool name, validating that name is a single non-empty path segment
with no .. or path separator, and that every character in it is UTS #39
Identifier_Status=Allowed (issue #433).
The UTS #39 allowlist rejects the same hostile inputs the project’s earlier
denylist-based invisible-payload check targeted — the Unicode Tags block, bidi
embedding/override/isolate controls, zero-width/invisible-operator characters, and
variation selectors (issues #432, #431, critic finding S1) — because none of those
characters carry Identifier_Status=Allowed, so an allowlist gate closes the same gap
without needing a parallel, hand-maintained denylist of forbidden character classes.
§Errors
Returns ToolNameError::InvalidFormat if name is empty, or contains a .., a
path separator, or a root/prefix component. Returns ToolNameError::DisallowedCharacter
if name passes that check but contains a character outside the UTS #39
Identifier_Status=Allowed set (see
first_disallowed_identifier_char).
§Examples
use mcp_execution_core::{ToolName, ToolNameError};
let name = ToolName::new("my_tool").unwrap();
assert_eq!(name.as_str(), "my_tool");
assert!(ToolName::new("a/b").is_err());
assert!(ToolName::new("evil\u{200D}tool").is_err());
// A Unicode-Tags-block-smuggled invisible payload is rejected, not silently accepted.
let err = ToolName::new("safe\u{E0001}\u{E0073}\u{E007F}").unwrap_err();
assert!(matches!(err, ToolNameError::DisallowedCharacter { .. }));
// A single variation selector is also rejected outright, unlike in display text.
let err = ToolName::new("safe\u{FE0F}").unwrap_err();
assert!(matches!(err, ToolNameError::DisallowedCharacter { .. }));Sourcepub fn as_str(&self) -> &str
pub fn as_str(&self) -> &str
Returns the tool name as a string slice.
§Examples
use mcp_execution_core::ToolName;
let name = ToolName::new("test_tool").unwrap();
assert_eq!(name.as_str(), "test_tool");Sourcepub fn into_inner(self) -> String
pub fn into_inner(self) -> String
Consumes the ToolName and returns the inner String.
§Examples
use mcp_execution_core::ToolName;
let name = ToolName::new("tool").unwrap();
let inner: String = name.into_inner();
assert_eq!(inner, "tool");