@Tool Decorator¶
The @Tool class decorator and related interfaces for defining tools declaratively. Attach metadata -- name, description, parameter schemas -- to a class, and the framework handles validation and registry integration automatically.
Import¶
import {
Tool,
ITool,
ToolMetadata,
ToolParameter,
getToolMetadata,
isTool,
validateToolParams,
createTool,
} from "@modernpath/agent-framework";
ITool Interface¶
The contract that every tool must satisfy.
interface ITool {
execute(params: Record<string, any>): Promise<any>;
validate?(params: Record<string, any>): void;
cleanup?(): Promise<void>;
}
| Method | Required | Description |
|---|---|---|
execute(params) | Yes | Run the tool with the given parameters and return the result. |
validate(params) | No | Validate parameters before execution. If not provided and @Tool is used, the decorator auto-generates a validator from ToolMetadata.parameters. |
cleanup() | No | Release resources (e.g., close connections). Called during shutdown if the host manages tool lifecycle. |
@Tool Decorator¶
Class decorator that attaches ToolMetadata to a tool class.
Behavior¶
- Stores
metadatain an internalWeakMapkeyed by the class constructor - Adds a static
getMetadata()method to the class - Validates that the class has an
executemethod (throws at decoration time if missing) - If the class does not define a
validatemethod, auto-generates one based onmetadata.parameters
Usage¶
@Tool({
name: "document-retrieve",
description: "Retrieves a document from SharePoint by ID",
version: "1.0.0",
category: "sharepoint",
tags: ["document", "sharepoint"],
requiresAuth: true,
parameters: {
siteId: {
type: "string",
description: "SharePoint site ID",
},
documentId: {
type: "string",
description: "Document unique identifier",
},
},
examples: [
{
description: "Retrieve a specific document",
params: { siteId: "site-123", documentId: "doc-456" },
expectedOutput: { content: "...", mimeType: "application/pdf" },
},
],
})
class DocumentRetrieveTool implements ITool {
async execute(params: Record<string, any>): Promise<any> {
// Implementation...
return { content: "...", mimeType: "application/pdf" };
}
}
TypeScript decorator configuration
The @Tool decorator uses legacy TypeScript decorators. Ensure your tsconfig.json has "experimentalDecorators": true. The decorator does not require reflect-metadata.
ToolMetadata¶
Metadata describing a tool's identity, parameters, and capabilities.
interface ToolMetadata {
name: string;
description: string;
parameters?: Record<string, ToolParameter>;
version?: string;
category?: string;
requiresAuth?: boolean;
rateLimit?: number;
schema?: {
inputJsonSchema?: any;
outputJsonSchema?: any;
};
examples?: Array<{
description: string;
params: Record<string, any>;
expectedOutput?: any;
}>;
tags?: string[];
}
Properties¶
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | Yes | -- | Unique tool identifier. |
description | string | Yes | -- | Human-readable description of what the tool does. Used by LLM planners and tool catalogs. |
parameters | Record<string, ToolParameter> | No | undefined | Parameter schema. Keys are parameter names, values are ToolParameter definitions. |
version | string | No | undefined | Tool version string. |
category | string | No | undefined | Category for grouping (e.g. "sharepoint", "external", "analytics"). Used by ToolRegistry.search(). |
requiresAuth | boolean | No | undefined | Indicates the tool requires authentication to function. |
rateLimit | number | No | undefined | Maximum calls per minute. Informational; enforcement is the caller's responsibility. |
schema | object | No | undefined | Extended JSON Schema objects for richer protocol adapters (e.g. MCP). inputJsonSchema describes the input; outputJsonSchema describes the output. These are intentionally loose-typed to accept any JSON Schema draft. |
examples | Array<Example> | No | undefined | Usage examples with sample parameters and expected outputs. Useful for documentation and testing. |
tags | string[] | No | undefined | Freeform tags for filtering (e.g. ["document", "sharepoint"]). Used by ToolRegistry.search(). |
ToolParameter¶
Describes a single parameter in a tool's parameter schema.
interface ToolParameter {
type: "string" | "number" | "boolean" | "array" | "object";
description: string;
required?: boolean;
default?: any;
pattern?: string;
min?: number;
max?: number;
enum?: any[];
items?: ToolParameter;
properties?: Record<string, ToolParameter>;
}
Properties¶
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
type | string | Yes | -- | Parameter data type. One of "string", "number", "boolean", "array", "object". |
description | string | Yes | -- | Human-readable description. |
required | boolean | No | true | Whether the parameter must be provided. Defaults to required (i.e., required !== false means required). |
default | any | No | undefined | Default value if the parameter is not provided. A parameter with a default is never treated as missing. |
pattern | string | No | undefined | Regex pattern for string validation. |
min | number | No | undefined | Minimum value for numbers. |
max | number | No | undefined | Maximum value for numbers. |
enum | any[] | No | undefined | List of allowed values. |
items | ToolParameter | No | undefined | Schema for array elements (when type is "array"). |
properties | Record<string, ToolParameter> | No | undefined | Schema for object properties (when type is "object"). |
Validation Rules¶
The built-in validateToolParams() function enforces these rules:
- Required check: If
required !== falseand nodefaultis defined, the parameter must be present - Type check: The JavaScript
typeof(orArray.isArrayfor arrays) must matchtype - Pattern check: For strings, the value must match the regex pattern
- Range check: For numbers, the value must be within
[min, max] - Enum check: The value must be one of the allowed enum values
- Nested validation: Array items and object properties are validated recursively
Helper Functions¶
getToolMetadata¶
Retrieve metadata from a tool instance or class.
Checks the internal WeakMap for the target, then falls back to target.constructor. Returns undefined if no @Tool decorator was applied.
const tool = new WeatherTool();
const meta = getToolMetadata(tool);
console.log(meta?.name); // "weather"
isTool¶
Check whether an object has @Tool metadata attached.
validateToolParams¶
Validate a parameter object against a parameter schema. Throws descriptive errors on validation failure.
function validateToolParams(
params: Record<string, any>,
paramMetadata: Record<string, ToolParameter>
): void
import { validateToolParams } from "@modernpath/agent-framework";
const schema = {
city: { type: "string" as const, description: "City name" },
days: { type: "number" as const, description: "Forecast days", min: 1, max: 14 },
};
validateToolParams({ city: "Helsinki", days: 7 }, schema); // OK
validateToolParams({ city: "Helsinki", days: 30 }, schema); // throws: "Parameter days must be at most 14"
validateToolParams({}, schema); // throws: "Missing required parameter: city"
createTool¶
Create an ITool object from a metadata definition and an execute function, without using the @Tool decorator.
function createTool(
metadata: ToolMetadata,
executeFn: (params: Record<string, any>) => Promise<any>
): ITool
The returned tool has an auto-generated validate method based on metadata.parameters.
import { createTool } from "@modernpath/agent-framework";
const echoTool = createTool(
{
name: "echo",
description: "Echoes the input",
parameters: {
message: { type: "string", description: "Message to echo" },
},
},
async (params) => ({ echo: params.message }),
);
// Register with the registry
registry.register("echo", echoTool);
Complete Example¶
import { Tool, ITool, ToolRegistry } from "@modernpath/agent-framework";
@Tool({
name: "currency-convert",
description: "Converts an amount between two currencies",
version: "2.0.0",
category: "finance",
tags: ["currency", "conversion", "external"],
requiresAuth: true,
rateLimit: 100,
parameters: {
from: {
type: "string",
description: "Source currency code (ISO 4217)",
pattern: "^[A-Z]{3}$",
},
to: {
type: "string",
description: "Target currency code (ISO 4217)",
pattern: "^[A-Z]{3}$",
},
amount: {
type: "number",
description: "Amount to convert",
min: 0,
},
precision: {
type: "number",
description: "Decimal places in result",
required: false,
default: 2,
min: 0,
max: 8,
},
},
examples: [
{
description: "Convert 100 EUR to USD",
params: { from: "EUR", to: "USD", amount: 100 },
expectedOutput: { converted: 108.50, rate: 1.085 },
},
],
})
class CurrencyConvertTool implements ITool {
constructor(private readonly apiKey: string) {}
async execute(params: Record<string, any>): Promise<any> {
const { from, to, amount, precision = 2 } = params;
const rate = await this.fetchRate(from, to);
return {
converted: Number((amount * rate).toFixed(precision)),
rate,
from,
to,
};
}
async cleanup(): Promise<void> {
// Close any open connections
}
private async fetchRate(from: string, to: string): Promise<number> {
// API call implementation...
return 1.085;
}
}
// Usage
const registry = new ToolRegistry();
registry.register("currency-convert", new CurrencyConvertTool("sk-..."));
await registry.execute("currency-convert", {
from: "EUR",
to: "USD",
amount: 100,
});
// => { converted: 108.50, rate: 1.085, from: "EUR", to: "USD" }
Related Pages¶
- ToolRegistry -- registering and managing tools
- Dynamic Tools -- runtime tool registration without decorators
- BaseAgent -- how agents call tools via
useTool() - MCP Integration -- consuming tool schemas from remote servers