llm-tool
Typed Rust tool definitions for LLM agents and MCP servers.
Overview
#[llm_tool]: Generates a typed parameter struct, JSON Schema, andRustToolimplementation from a plain function.- Parameter Validation: Deserializes and validates tool arguments before calling the function.
- Registry:
ToolRegistryprovides JSON Schemas and dispatches calls by name. - MCP Server:
llm-tool-mcpexposes tools, prompts, and resources over stdio, TCP, or Unix sockets. no_stdSupport: Core types build onno_std+alloctargets.
Quick Start
[]
= "0.10.3"
= "0.10.3" # 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.
Middle-Out Truncation & Observation Recall
When tools return large payloads (file dumps, logs, shell output),
TruncationPolicy bounds output size while preserving both the prefix and the
tail:
use ;
let policy = new
.with_head_ratio
.with_alignment;
let truncated = truncate_middle;
assert!;
Observation Spilling
To retain the full output before truncation, attach an [OutputSpillSink]. A
typed [SpillRef] handle is embedded into the truncation marker for recall
tools:
use Arc;
use ;
;
let policy = new
.with_spill_sink;
let payload = "A".repeat;
let outcome = policy.truncate_detailed.unwrap;
assert!;
assert_eq!;
Spill Failure Semantics
| API | On spill failure |
|---|---|
[TruncationPolicy::truncate_detailed] |
Returns Err(SpillError); the caller decides. |
[TruncationPolicy::truncate] |
Never fails. Logs the error and renders it into the marker, so the model is told the omitted bytes are unrecoverable. |
The in-band warning is appended even to custom marker templates that do not
mention it, and truncation drops content before the marker so max_bytes always
includes an explicit notice.
Prompt-Injection Defense
Sanitize untrusted tool outputs to neutralize ChatML, Llama, Harmony, and
DeepSeek control tokens, preventing indirect prompt injection attacks.
Declarative Output Sanitization
Mark tools that return untrusted external data with #[llm_tool(sanitize)]
(in-place delimiter neutralization) or #[llm_tool(sanitize = "tag")] (wraps in
<tag> with an explicit boundary notice):
use ;
/// Fetch untrusted external content.
# block_on;
Template-Level Sanitization via md-tmpl
In response or response_file templates, use | sanitize (or
| sanitize("tag")) to sanitize untrusted fields and escape enclosing XML tags:
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 & Safe Parallel Batch Dispatch
Classify tools with
#[llm_tool(effect = "read_only" | "mutating" | "destructive")] (alias
idempotent = true maps to ReadOnly). ToolRegistry::dispatch_batch executes
batches concurrently with [BatchExecutionMode::Parallel] while automatically
blocking Destructive tools unless explicitly confirmed 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.