llm-tool
Define tools for LLM agents in Rust.
Overview
#[llm_tool]: Turns a Rust function into a tool.- Validation: Checks tool arguments before calling the function.
- Registry: Lists tools and calls them by name.
- MCP Server:
llm-tool-mcpserves tools, prompts, and resources over stdio, TCP, or Unix sockets. no_std: Core types work without the standard library.
Quick Start
[]
= "0.10.6"
= "0.10.6" # Optional: MCP server support
Define a Tool
Doc comments become tool and parameter descriptions:
use ;
/// Fetches the current weather for a given location.
async
let registry = new.with_tool;
let definitions = registry.definitions;
assert_eq!;
# block_on;
MCP: Tools, Prompts, and Resources
Use llm-tool-mcp to expose tools, prompts, and resources over the Model
Context Protocol:
# use ;
/// A Tool for the LLM to execute.
/// A Prompt template for the LLM to use.
/// A Resource for the LLM to read.
// Register tools in the ToolRegistry.
let registry = new.with_tool;
assert_eq!;
// Prompts and Resources are registered via llm-tool-mcp's builder:
// McpServer::builder("my-server", "1.0", registry)
// .with_prompt(CodeReview)
// .with_resource(GetConfig)
// .build();
Features
Return Types & Error Handling
Return Result<T, E> or T:
- Auto-Serialization: Any
T: Serializeis serialized to JSON. - Structured Metadata: Attach metadata to
ToolOutputorToolError(logged for caller inspection, not sent to the model).
Context
Add ctx: &ToolContext to a tool function to access shared state, conversation
IDs, or typed extensions without exposing it in the JSON Schema.
Custom Descriptions
Override doc comments with an inline string:
# use ;
async
Load descriptions from .tmpl.md template files (description_file = "...")
with compile-time variable substitution and validation. See the
md-tmpl docs for details.
Output Truncation
Keep the start and end of large tool outputs within a size limit:
use ;
let policy = new
.with_head_ratio
.with_alignment;
let truncated = truncate_middle;
assert!;
Saving Full Output
Attach an [OutputSpillSink] to save the full output before truncation. A
[SpillRef] ID is added to the truncation notice so recall tools can fetch it:
use Arc;
use ;
;
let policy = new
.with_spill_sink;
let payload = "A".repeat;
let outcome = policy.truncate_detailed.unwrap;
assert!;
assert_eq!;
Error Handling When Saving Fails
| API | On failure |
|---|---|
[TruncationPolicy::truncate_detailed] |
Returns Err(SpillError). |
[TruncationPolicy::truncate] |
Logs the error and notes in the truncation marker that the omitted bytes could not be saved. |
Output Sanitization
Sanitizes untrusted tool output so special model control tokens cannot inject instructions into the prompt.
Defaults
Every tool output is sanitized unless you opt out:
| Goal | Setting |
|---|---|
| Default (neutralize control tokens) | nothing to do |
| Wrap untrusted content in an envelope | #[llm_tool(quarantine)] or #[llm_tool(sanitize = "tag")] |
| Classify tool data provenance | #[llm_tool(provenance = "untrusted_network")] (auto-quarantines external_mcp / untrusted_network) |
| Raise the minimum for all tools | ToolRegistry::new().with_output_floor(OutputSanitization::Quarantine) |
| Raw output (trusted content only) | #[llm_tool(sanitization = "none")] and with_output_floor(OutputSanitization::None) |
Manual RustTool impls can keep using the SANITIZE_OUTPUT /
QUARANTINE_OUTPUT shorthands; SANITIZE_OUTPUT now defaults to true.
Data Sources & Secret Tokens
Set where a tool's data comes from with #[llm_tool(provenance = "...")]
("trusted", "workspace_local", "private_data", "external_mcp", or
"untrusted_network"). External and network tools wrap their output in
<untrusted_tool_output> tags by default.
Use [SurrogateVault] with [ToolContext] to replace secret values with
<surrogate:kind:id> placeholders so raw secrets are not sent to the model:
use ;
let vault = new;
let ctx = new.with_surrogate_vault;
let token = ctx.mint_surrogate.unwrap;
assert_eq!;
assert_eq!;
assert_eq!;
Wrapping Untrusted Output
Wrap untrusted tool output with #[llm_tool(sanitize = "tag")] or
#[llm_tool(quarantine)]:
use ;
/// Fetch untrusted external content.
# block_on;
Response Templates
In response or response_file templates, str parameters are sanitized by
default. Use | sanitize("tag") to wrap a field in an XML tag, or trusted str
for trusted text:
use ;
/// Fetch untrusted external content with template-level sanitization.
# block_on;
Programmatic Sanitization
Use [ToolOutput] methods to sanitize outputs programmatically:
use ToolOutput;
let output = new
.sanitized_block;
assert!;
assert!;
Tool Effects & Batch Calls
Mark tools with #[llm_tool(effect = "read_only" | "mutating" | "destructive")]
(idempotent = true is an alias for ReadOnly). ToolRegistry::dispatch_batch
runs batches in parallel with [BatchExecutionMode::Parallel] and blocks
Destructive tools unless allowed via
[BatchExecutionMode::ParallelAllowDestructive] or [AllowDestructiveBatch]:
use ;
/// Drop a database table.
let registry = new.with_tool;
assert_eq!;
assert!;
Documentation
llm-tool— Return types, tool context, metadata, template descriptions.llm-tool-mcp— MCP transports, stdio/TCP, routing.md-tmpl— Template syntax, env variables, response templates.
License
Dual-licensed under Apache-2.0 OR MIT.