ReActAgent can invoke to do something outside the LLM. In practice that means:
- A plain Python function
- A method on a class
- Another agent (wrapped as a callable)
- A method exposed by an MCP server
tools=[...] and the agent sees them as named, schema-typed functions it can call by name.
Functions are tools
The fastest way to give an agent a tool is to pass a plain Python function.The @tool decorator
Use @tool to customize how a function is exposed to the model: its name, description, schema, guardrails, an approval gate, or lifecycle hooks.
tool() also works as a post-hoc patcher on a callable you don’t own:
Describing parameters
You have three ways to describe what a tool’s arguments mean. Pick whichever is most convenient.Pydantic model (recommended)
Define aBaseModel subclass with Field descriptors. This gives you validation constraints, nested objects, enums, and rich descriptions all in one place.
Filter are expanded into the JSON Schema the model sees. The function signature is what Motus calls when the tool runs, so make sure the field names match the parameter names.
Annotated for inline descriptions
A lighter alternative when you only need to add descriptions and do not need validation. Add a string after the type in an Annotated wrapper.
Raw JSON Schema
For exact control over the schema the model sees, pass a dict directly.Type mapping
When Motus infers the schema from your type hints, this is the mapping it uses.Tool collections from a class
Group related tools into a class with the@tools decorator. Public methods become tools automatically, and self is stripped from the schema.
tools() also works as a function call on an instance you don’t own, for cases where you want to pick specific methods:
A per-method
@tool overrides the class-level @tools options for that one method:
Built-in tools
Motus ships a ready-made set of tools that cover the common needs of a code-writing agent: running shell commands, reading and writing files, searching the filesystem, and keeping a checklist of its own work. Most agents that do anything with code can drop these in without writing their own. Get them frombuiltin_tools(), which works out of the box against your local machine.
Pass
skills_dir="..." to add a load_skill tool that lets the agent load self-contained instructions from disk on demand. See Skills.
Sandboxed execution
ASandbox in Motus is an execution environment that the built-in tools run inside: you create it, the tools bound to it execute commands there, and you close it when you’re done. It is not a tool itself; it is the place tools run. Two implementations ship with Motus:
LocalShell, the default, runs commands directly on your host machine.DockerSandboxruns everything inside a container, so a rogue command cannot touch your host.
builtin_tools() uses LocalShell when you do not pass anything. To isolate execution, create a DockerSandbox and hand it in:
get_sandbox() factory. It reuses a single global provider under the hood, so repeated calls do not spin up new containers.
MCP tools
Any Model Context Protocol server can be used as a tool source viaget_mcp().
get_mcp(...) session to the agent without async with, the agent connects it lazily on its first run. Using async with gives you deterministic cleanup when the block exits. See MCP Integration for connection options, filtering, and renaming tools.
Agents as tools
An agent can be another agent’s tool. The caller treats it like any other entry intools=[...].
researcher.as_tool(name="do_research", stateful=True). See Multi-agent for the full composition guide.
Approval gates
Mark a dangerous tool withrequires_approval=True and the agent will pause before running it, emit an approval request to the caller, and resume once the caller approves.
motus serve surfaces these pauses through its REST API so a client can prompt the user and respond. See Human in the Loop for the full protocol.

