Tools¶
Auto-generated from source docstrings (mkdocstrings). The complete public contract is agentmaker.__all__ plus each subpackage __all__.
agentmaker.tools: the tool system: base class, response protocol, registry, permissions, and builtin / advanced tools.
Exports: Tool (base class) / tool (@tool decorator, turns a function into a tool in one line) / ToolParameter / ToolResponse / ToolRegistry / ToolPermissions / ConfirmCallback (confirmation callback type for high-risk actions) / CalculatorTool / SearchTool / CLITool / NotesTool / MCPClient / MCPTool.
Tool
¶
Bases: ABC
Abstract base class for tools. Subclasses must implement run() and get_parameters().
Class attributes
requires_confirmation: Whether this is a high-risk action (send email / delete file / shell, etc.); when True, execution requires human confirmation (the confirmation logic is handled by the Agent execution stage, see project red line section 8). external_content: Whether the result is "content from an external source" (web search / knowledge base / third-party MCP tool). When True, the framework wraps the result in an anti-injection delimiting guardrail before feeding it back to the model (same as memory/RAG's context_guard), reducing the risk of indirect prompt injection (OWASP LLM01: external text hiding "ignore previous instructions..." to steer the model). The builtin SearchTool / RAGTool / MCPTool set this True. supports_parallel: Whether this tool may run concurrently with other tools in the same turn (when the model emits multiple independent read-only calls in one turn, the Agent runs adjacent parallelizable calls together with asyncio.gather and backfills results in original order). Defaults to False (strictly serial, behavior unchanged); setting it True promises "safe under concurrent invocation, no side-effect ordering dependency, does not depend on results of other calls in the same turn": typically a read-only tool with no shared mutable state (such as web search). High-risk tools requiring confirmation never run in parallel (enforced separately by the framework), so a write-type tool is not run concurrently even if it sets this True.
__init__(name, description, *, origin='builtin')
¶
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Tool name (unique identifier, used by the registry as a key). |
required |
description
|
str
|
Description of the tool's function (shown to the LLM, determines when to call it). Fixed at construction time and does not follow prompt changes: a builtin tool's description is read from the prompt registry at the moment of creation and stored; later update_prompts / language switches do not change an already-built tool's description (whereas parameter descriptions are read live and do change). To switch language wholesale, override before creating the tool (see approach one in the packs). |
required |
origin
|
str
|
Tool origin identifier (trust root): "builtin" for framework builtins / app custom tools may set their own / MCP tools are stamped by MCPClient as "mcp:{namespace}" (stamped by the framework, cannot be overridden by the tool definition). Used by ToolPermissions for origin-based authorization (allow_origins / deny_origins): a name can be spoofed by a remote, the origin is the root of trust. |
'builtin'
|
needs_confirmation(parameters)
¶
Whether this specific call needs human confirmation; defaults to the static requires_confirmation (whole-tool, all-or-nothing).
Multi-action tools (such as MemoryTool's forget / consolidate) can override this method to return True only for destructive actions, implementing action-level confirmation. The confirmation gate (registry / harness) always reads this method rather than requires_confirmation directly.
run(parameters)
¶
Execute the tool (synchronous). Synchronous tools implement this method.
A subclass must implement at least one of run (synchronous tools) or arun (native async tools); a tool that implements only arun has its synchronous run raise by default to steer callers to arun.
Threading contract: the framework execution chain (harness -> registry -> arun default implementation) dispatches run onto a thread pool, possibly a different worker thread each time. Do not hold thread-bound resources on the tool instance (such as a default-argument sqlite3 connection, signal, or GUI handle); either build connections lazily per-thread with threading.local, or create them with check_same_thread=False and add your own lock (the framework's builtin stores do exactly this).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
parameters
|
dict
|
The call parameter dict (keys correspond to the parameter names declared by get_parameters()). |
required |
Returns:
| Name | Type | Description |
|---|---|---|
ToolResponse |
ToolResponse
|
The execution result (text is read by the model, status marks success/partial/error, data is an optional structured result). |
arun(parameters)
async
¶
Execute the tool (async entry point).
The default implementation dispatches synchronous run onto a thread pool (asyncio.to_thread), so synchronous tools do not block the event loop in an async environment: existing synchronous tools can be called by an async Agent with zero changes. Native async tools (such as MCPTool) should override this method and await the real async call internally (no need to implement run). The semantics match run: awaiting it means "wait until execution completes, get the result".
Args and Returns: same as run.
get_parameters()
abstractmethod
¶
Declare the parameters this tool accepts, for the registry to generate a description / schema.
Returns:
| Type | Description |
|---|---|
List[ToolParameter]
|
List[ToolParameter]: The list of parameter definitions; returns an empty list if there are no parameters. |
from_callable(func, *, name=None, description=None, requires_confirmation=False, external_content=False, supports_parallel=False, origin='builtin')
classmethod
¶
Wrap an ordinary type-annotated function into a Tool in one line: parameter names / types / defaults / required-ness are all inferred from the function signature, the first docstring line becomes the tool description, and parameter descriptions come from Annotated or the docstring "Args:" section (same implementation as the @tool decorator).
Difference from register_function: register_function's function takes the whole dict and requires a hand-written parameter list; this path expands kwargs by signature and auto-infers the schema (so a parameter-name drift surfaces immediately at the call site rather than a silent KeyError). async functions are awaited natively.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
Callable
|
The function to wrap (synchronous or async); must have parameter type annotations, otherwise it fails loud at registration time. |
required |
name
|
Optional[str]
|
Tool name, defaults to func.name (must match the function-calling name rule, raises ToolRegistrationError if invalid). |
None
|
description
|
Optional[str]
|
Tool description, defaults to the first paragraph of the docstring. |
None
|
requires_confirmation
|
bool
|
Set True for high-risk actions (disk writes / sending requests, etc.) to pass through the confirmation gate before execution. |
False
|
external_content
|
bool
|
Set True when the result is content from an external source, to wrap it in an anti-injection guardrail before feeding it back to the model. |
False
|
supports_parallel
|
bool
|
Set True for read-only, concurrency-safe tools to allow concurrent execution with other parallelizable tools in the same turn (see the Tool class attributes). |
False
|
origin
|
str
|
Origin identifier (trust root), defaults to "builtin". |
'builtin'
|
Returns:
| Name | Type | Description |
|---|---|---|
Tool |
Tool
|
A Tool instance that calls func by signature. |
ToolParameter
dataclass
¶
A single parameter definition for a tool, used for self-description (generating the parameter description / schema shown to the LLM).
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Parameter name. |
type |
str
|
Parameter type (OpenAI schema style, e.g. string / integer / number / boolean / array / object). |
description |
str
|
Parameter description. |
required |
bool
|
Whether the parameter is required, defaults to True. |
default |
Any
|
Default value, meaningful only when not required, defaults to None. |
schema |
Optional[dict]
|
The full JSON Schema for this parameter; if given, to_openai_schema uses it verbatim (preserving enum / array items / nested object), otherwise it is generated from type + description. Tools with complex schemas (such as MCP) use this; ordinary tools leave it empty. |
ToolResponse
dataclass
¶
A tool execution result.
Attributes:
| Name | Type | Description |
|---|---|---|
text |
str
|
The result text for the model to read (always present; this is what gets spliced into the conversation / scratchpad). |
status |
ToolStatus
|
Execution status: "success" normal / "partial" succeeded but incomplete (e.g. output was truncated) / "error" failed. |
data |
Any
|
Structured data (optional), for programmatic use (such as raw search entries, a computed value); the model only reads text, not data. |
__str__()
¶
Let an f-string / string concatenation take the result text directly.
ok(text, data=None)
classmethod
¶
Construct a success result (optionally with structured data).
error(text, data=None)
classmethod
¶
Construct a failure result (text is a readable error description, optionally with structured data).
Most failures have no structured result and leave data as None; but some failures still carry usable context (such as an MCP tool's structuredContent / raw content when isError), pass data when needed.
partial(text, data=None)
classmethod
¶
Construct a "succeeded but incomplete" result (such as truncated output / some sources failing).
ToolRegistry
¶
Tool registry: manage a batch of Tools by name and produce the tool list for the LLM.
__init__(*, prompts=None)
¶
Initialize an empty registry. prompts: optional prompt registry (PromptRegistry, see agentmaker.prompts); tool error text is taken from it, DEFAULT_PROMPTS if not passed.
register(tool, *, overwrite=False)
¶
Register one tool, keyed by tool.name.
The tool name must match the function-calling rule ^[a-zA-Z0-9_-]{1,64}$ (same for OpenAI / Anthropic); an illegal one raises, otherwise to_openai_schema would emit a function name the server rejects; for external sources (MCP), normalize with sanitize_tool_name first. Duplicate names raise by default (to prevent accidental re-registration / a name collision being silently overwritten); pass overwrite=True explicitly when replacement is intended.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tool
|
Tool
|
the Tool instance to register. |
required |
overwrite
|
bool
|
whether to allow overwriting on a duplicate name; default False (duplicate raises ValueError). |
False
|
register_all(tools, *, on_conflict='error')
¶
Register a batch of tools, returning the list of tool names actually registered.
on_conflict controls duplicate-name behavior: "error" (default, a duplicate raises ToolRegistrationError) / "skip" (skip duplicates, keep existing) / "overwrite" (overwrite existing). Use "skip" when batch-attaching tools after MCP load_tools, to prevent a malicious server from squatting an existing name so a single collision raises and blows up the whole load loop (DoS).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tools
|
the iterable of Tools to register. |
required | |
on_conflict
|
str
|
duplicate-name policy, error / skip / overwrite. |
'error'
|
register_function(func, name, description, parameters=None, *, requires_confirmation=False, supports_parallel=False, overwrite=False)
¶
Register a plain function as a tool (a shortcut that avoids writing a Tool subclass first).
The function is wrapped into a uniform Tool stored in the same table, so like class tools it can be listed / rendered to a description / converted to a schema.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
Callable[[dict], str]
|
the tool function; takes a parameter dict and returns a string result. |
required |
name
|
str
|
the tool name. |
required |
description
|
str
|
the tool description. |
required |
parameters
|
Optional[List[ToolParameter]]
|
the list of parameter definitions; omit if there are no parameters (defaults to empty). |
None
|
requires_confirmation
|
bool
|
whether it is high-risk and needs confirmation before execution; set True when quick-registering functions that write to disk / send requests / run commands. |
False
|
supports_parallel
|
bool
|
set True for read-only, concurrency-safe functions to allow concurrent execution with other parallel tools in the same round (see the Tool class attribute). |
False
|
overwrite
|
bool
|
whether to allow overwriting on a duplicate name; default False (duplicate raises ValueError). |
False
|
func may be a sync or async function: an async function is awaited via the async entry point (aexecute_tool), so it is never fed as str(coroutine) garbage to the model.
Example
reg.register_function(lambda p: p["city"] + " sunny", "weather", "check the weather", [ToolParameter("city", "string", "city name")])
register_callable(func, *, name=None, description=None, requires_confirmation=False, external_content=False, supports_parallel=False, overwrite=False)
¶
Register a type-annotated function as a tool: the parameter schema is inferred automatically from the signature (via the same implementation as Tool.from_callable / @tool).
Division of labor with register_function: use register_function to hand-write parameters with a function that receives the whole dict; use this method (or @tool-decorate then register) for a type-annotated function whose schema you want inferred automatically and which is called by expanding kwargs from the signature.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
Callable
|
the type-annotated function (sync or async). |
required |
name / description
|
default to the function name / the first line of the docstring. |
required | |
requires_confirmation
|
bool
|
set True for high-risk actions. |
False
|
external_content
|
bool
|
set True when the result is content from an external source. |
False
|
supports_parallel
|
bool
|
set True for read-only, concurrency-safe functions to allow concurrent execution with other parallel tools in the same round (see the Tool class attribute). |
False
|
overwrite
|
bool
|
whether to allow overwriting on a duplicate name. |
False
|
from_tools(tools, *, prompts=None)
classmethod
¶
The single-source-of-truth entry that normalizes tools into a ToolRegistry (list[Tool]->registry / ToolRegistry->as-is / None->None).
Both Agent(tools=) and build_agent(spec.tools=) convert through it, avoiding two copies of normalization code drifting apart. The list may contain @tool-decorated function objects (which are themselves Tools).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tools
|
None / ToolRegistry / an iterable of Tools (including @tool-decorated function objects). |
required | |
prompts
|
the prompt registry used when building a new registry; DEFAULT_PROMPTS if not passed. |
None
|
get(name)
¶
Get a tool by name, returning None if it does not exist.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
the tool name. |
required |
list_tools()
¶
Return all registered tools.
execute_tool(name, parameters, confirm=None)
¶
The unified execution entry: locate a tool by name and run it; the sole channel through which an Agent / tool chain calls tools.
Tools that need confirmation (tool.needs_confirmation(parameters), which by default is requires_confirmation; multi-action tools can decide per action) first go through the confirm callback to ask consent (a §8 red line); when no confirm is passed, execution is denied by default for safety (only allowed once the upper layer explicitly provides a confirmation mechanism).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
the tool name. |
required |
parameters
|
dict
|
the parameter dict passed to the tool's run(). |
required |
confirm
|
Optional[ConfirmCallback]
|
the confirmation callback for high-risk tools, signature (tool, parameters) -> bool; executes only when it returns True. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
ToolResponse |
ToolResponse
|
the tool execution result; a readable status="error" explanation when the tool does not exist or execution is denied. |
aexecute_tool(name, parameters, confirm=None)
async
¶
The async version of execute_tool: tool lookup + confirmation logic is shared with the sync version (_resolve); execution goes through await tool.arun.
For sync tools, arun offloads run to the thread pool by default; for natively async tools (such as MCPTool), arun directly awaits the real async call.
execute_tool_checked(name, parameters, confirm=None)
¶
Execute a tool and return (result, whether it actually entered tool.run).
Normal calls keep using execute_tool(); the Harness's RunPolicy needs to distinguish
"stopped at the parameter-validation / confirmation gate" from "the tool actually ran and
then returned an error", so it counts via this method. It keeps the public return value
backward-compatible rather than stuffing an execution flag into the ToolResponse.
Exceptions raised inside the tool body are caught here in place and turned into an error ToolResponse (executed=True, since it did enter tool.run): the contract is that a tool returns ToolResponse.error itself and does not raise, but custom / MCP / AgentTool tools may not honor it, so we catch a layer at the sole execution channel, feeding the exception back for the model to reroute rather than letting one tool crash the whole run. HITL's ApprovalRequired is raised at a higher layer (harness) and never reaches here.
aexecute_tool_checked(name, parameters, confirm=None)
async
¶
The async version of execute_tool_checked, returning (result, whether it actually entered tool.arun); tool exceptions are likewise caught in place into an error.
The confirmation callback is offloaded to the thread pool by _aresolve: this keeps a blocking confirm (such as the default command-line y/n input) from stalling the event loop, and also makes re-entering a sync facade inside the callback (such as using another agent to judge approval) legal (the worker thread has no running loop).
get_catalog()
¶
Tool catalog: one line per tool "- name: description", no parameters, for keeping resident in the system prompt (tier 1 of progressive disclosure).
It contrasts with get_tools_description(): the catalog is cheap and resident; the full parameter schema is rendered on demand / by subset by the latter. Same shape as SkillLoader.catalog(), keeping the "catalog layer" of tools and skills consistent.
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
one line per tool "- name: description"; a placeholder message when there are no tools. |
get_tools_description(names=None)
¶
Assemble tools into a readable block of text (including a parameter list): for offline rendering / inspection; the context-budget accounting also uses it to estimate tool-schema cost.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
names
|
Optional[List[str]]
|
render only these tools, in the given order; None for all. Used for expanding a subset in progressive disclosure (paired with Tool-RAG). |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
one block per tool with name, description, and parameter list; a placeholder message when there are no tools. |
to_openai_schema(names=None)
¶
Convert tools into the tools list for OpenAI function calling.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
names
|
Optional[List[str]]
|
render only these tools, in the given order; None for all. Used for expanding a subset in progressive disclosure (paired with Tool-RAG). |
None
|
Returns:
| Type | Description |
|---|---|
List[dict]
|
List[dict]: each element shaped like {"type": "function", "function": {...}}, the parameter sub-schema produced by _param_schema. |
ToolPermissions
dataclass
¶
Allow / deny lists for tool calls, judged along two dimensions: the tool name and the origin.
Origin is the true root of trust: a name can be spoofed by a remote MCP server (naming a malicious tool "search" to piggyback on the allowlist), whereas origin is stamped by the framework ("builtin" / "mcp:{namespace}") and cannot be forged by the tool definition. So the more robust allowlist is by origin (allow_origins).
Decision semantics (aligned with Claude permissions' "deny wins" + a subagent's "allow restricts to a usable subset"): - matches the deny list or deny_origins -> deny (highest priority). - an allowlist is enabled (either allow or allow_origins is non-None) -> the tool must match the allow list or one of allow_origins to be permitted. - neither is enabled -> permit (constrained only by deny).
allow / allow_origins=None means that dimension enables no allowlist; allow=[] (an empty allowlist) means that dimension denies everything: use None to mean "no restriction". Exact match (no parameter-level / wildcard matching; that is an upper-layer policy). denial_reason accepts a tool-name str (judged by name only) or a Tool object (additionally judged by origin).
__post_init__()
¶
Normalize each list into a set to speed up judgment; keep None for allow / allow_origins (distinct from an empty set "deny everything"). prompts defaults to DEFAULT_PROMPTS.
denial_reason(tool)
¶
Decide whether a call is allowed: return the denial reason (readable, can be fed back to the model); return None to permit.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tool
|
a tool-name str (judged by name only, backward-compatible) or a Tool object (additionally judged by origin: origin is the root of trust, a name can be spoofed). |
required |
Returns:
| Type | Description |
|---|---|
Optional[str]
|
Optional[str]: the denial-reason text, None to permit. |
CalculatorTool
¶
SearchTool
¶
Bases: Tool
Web search. Multi-source automatic fallback (Tavily->DuckDuckGo->Brave->SerpAPI), returning a summary of the top results.
__init__(max_results=5, *, prompts=None)
¶
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
max_results
|
int
|
Maximum number of results returned per call. |
5
|
prompts
|
Optional prompt registry (PromptRegistry); the tool description / parameter text come from it, defaulting to DEFAULT_PROMPTS if not passed. |
None
|
run(parameters)
¶
Try each source in fallback order and return the first successful result; if all fail, summarize each source's reason.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
parameters
|
dict
|
Contains "query". |
required |
Returns:
| Name | Type | Description |
|---|---|---|
ToolResponse |
ToolResponse
|
ok on success (data carries the raw entries {source, answer, results}); error if all sources are unavailable. |
CLITool
¶
Bases: Tool
Wrap "run one allowlisted local command" as a Tool (high-risk, requires confirmation).
__init__(allowed_commands, *, timeout=10.0, max_output_chars=4000, env=None, arg_policy=None, prompts=None)
¶
Build a CLITool restricted to an allowlist of programs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
allowed_commands
|
List[str]
|
Allowlist of program names permitted to run (e.g. ["git", "ls", "grep"]); empty = deny all. |
required |
timeout
|
float
|
Per-command timeout in seconds; on timeout the command is terminated (killing spawned grandchildren too). |
10.0
|
max_output_chars
|
int
|
Maximum characters retained for each of stdout / stderr; the excess is truncated. |
4000
|
env
|
Optional[dict]
|
Environment variable mapping for the subprocess. By default only a minimal set is passed (PATH / HOME / LANG, taken from the current process), never leaking the whole os.environ (which includes .env secrets); if passed explicitly, exactly what you pass is used (app's own responsibility). |
None
|
arg_policy
|
Optional[Callable[[List[str]], Optional[str]]]
|
Dangerous-argument gate hook |
None
|
get_parameters()
¶
Declare parameters: a single command string.
run(parameters)
¶
Run synchronously: after validation, run the command via subprocess.Popen (shell=False, own process group), returning the exit code plus output.
Using Popen (not subprocess.run) with start_new_session makes the command a process-group leader, so on timeout the whole process group is killed, including grandchildren it spawned (subprocess.run's built-in timeout only kills the direct child and would miss grandchildren).
arun(parameters)
async
¶
Run natively async: create_subprocess_exec (shell=False, own process group) with a wait_for timeout; validation/assembly shared with run.
NotesTool
¶
Bases: Tool
Read / append note files under a restricted directory (append writes to disk, requires confirmation).
needs_confirmation(parameters)
¶
Only disk-writing actions require confirmation; read is a read-only operation within the restricted root and is allowed natively (action-level confirmation).
Uses "anything but read requires confirmation" rather than "only append requires confirmation": consistent with the high-risk default posture, so any new write action added later also automatically requires confirmation (fail-safe).
__init__(root, *, max_read_chars=8000, max_append_chars=50000, max_file_bytes=2000000, prompts=None)
¶
Build a NotesTool confined to a root directory.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
root
|
str
|
Notes root directory; all reads and writes are confined within it (if it does not exist, parent directories are created on demand on the first append). |
required |
max_read_chars
|
int
|
Maximum characters returned by read, truncated beyond it (to protect the context). |
8000
|
max_append_chars
|
int
|
Maximum characters of content per append, refused beyond it (to prevent a runaway single write). |
50000
|
max_file_bytes
|
int
|
Maximum bytes for a single note file; an append that would exceed it is refused (to prevent unbounded writes filling the disk). |
2000000
|
get_parameters()
¶
Declare parameters: action (read/append), path (relative path under root), content (text to append when appending).
run(parameters)
¶
Read or append a note per action; an invalid action, a path escape, or an empty append content all return a readable error.
MCPClient
¶
Manage a connection to one MCP server (local stdio subprocess or remote Streamable HTTP) and load its tools as MCPTool.
Use async with to manage the connection lifecycle (on entry, start the subprocess / open the HTTP session and handshake; on exit, clean up). Tools must be called while the async with block is alive (they cannot be called after the connection closes).
__init__(command=None, args=None, *, namespace, env=None, url=None, headers=None, auth=None, requires_confirmation=True, max_desc_chars=4096, expected_fingerprints=None, timeout=30.0, prompts=None)
¶
Configure an MCP server connection over exactly one transport.
Pick one transport: for a local subprocess pass command (plus optional args/env), for a remote server pass url (plus optional headers/auth); the two are mutually exclusive, and giving neither or both is an error.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
command
|
Optional[str]
|
[stdio] Command to start the server (e.g. "python" / "uvx" / "npx"). Mutually exclusive with url. |
None
|
args
|
Optional[List[str]]
|
[stdio] Command arguments (e.g. ["my_server.py"]). |
None
|
env
|
Optional[dict]
|
[stdio] Optional environment variables passed to the server subprocess. |
None
|
url
|
Optional[str]
|
[HTTP] The remote server's Streamable HTTP endpoint (e.g. "https://mcp.example.com/mcp"). Mutually exclusive with command. |
None
|
headers
|
Optional[dict]
|
[HTTP] Optional extra request headers (e.g. a custom API key header). |
None
|
auth
|
[HTTP] Optional httpx.Auth (such as the mcp SDK's OAuthClientProvider); the framework only forwards it, with token acquisition/refresh/persistence all in the app. |
None
|
|
namespace
|
str
|
Tool namespace prefix (required, the trust root): the tool display name becomes "{namespace}{original name}" and the origin is stamped "mcp:{namespace}". Required and specified explicitly by the integrator, not derived from the server's self-reported serverInfo.name (which is attacker-controlled, equivalent to letting a malicious server pick its own trusted prefix). Prevents collisions across servers (two servers both having search -> "calendar_search" / "web_search"); remote calls still use the original name. Use underscores, not dots (must match ^[a-zA-Z0-9-]{1,64}$). |
required |
requires_confirmation
|
bool
|
Whether the loaded MCPTools require human confirmation by default; default True, since remote tools are untrusted and the default posture is even stricter than our own CLITool; only after the app has vetted the server should it explicitly pass False to downgrade. A remote HTTP server is only less trustworthy and even more deserving of default confirmation. |
True
|
max_desc_chars
|
int
|
Length limit for tool / parameter descriptions, truncated beyond it (to prevent overly long descriptions from flooding the context); default 4096. |
4096
|
expected_fingerprints
|
Optional[dict]
|
Optional {display name: sha256} pinning list (tool pinning): if given, load_tools verifies each tool-definition fingerprint and raises ToolError refusing to load on mismatch (to prevent the server later swapping the description / schema, a rug-pull); if not given, the fingerprint is only exposed via MCPTool.fingerprint for the app to record and compare itself (mechanism in agentmaker, policy in the app). |
None
|
timeout
|
Optional[float]
|
Timeout in seconds for the handshake (initialize) and tool calls (call_tool), default 30; a stuck server will not make the agent wait forever. For the HTTP transport it also serves as the per-request timeout (streamablehttp_client's timeout). Pass None to disable the timeout (wait forever, not recommended). |
30.0
|
prompts
|
Optional prompt registry (PromptRegistry); the text call_tool feeds back to the model (session error / no output / tool-error prefix) comes from it, defaulting to DEFAULT_PROMPTS. |
None
|
__aenter__()
async
¶
Establish the connection (stdio subprocess or remote HTTP), create the ClientSession, and handshake (initialize).
__aexit__(*exc)
async
¶
Close the session and underlying transport (stdio subprocess / remote HTTP connection, all cleaned up uniformly by AsyncExitStack).
load_tools()
async
¶
List the tools the server exposes, adapting each into an MCPTool (sharing this connection).
The display name is prefixed "{namespace}_{original name}" to prevent collisions across servers, then run through sanitize_tool_name to normalize it to the character set function calling allows, deduplicating with _2/_3 on collision; remote calls always use the original name. Each tool description is sanitized (strip control characters plus truncate), the origin is stamped "mcp:{namespace}", and requires_confirmation is on by default; a tool-definition fingerprint is computed, and if expected_fingerprints was passed it is verified with a mismatch refusing to load. Raises ToolError if the session is not established or is closed.
call_tool(name, arguments)
async
¶
Call one of the server's tools and return a ToolResponse.
text concatenates the text blocks in content (for the model to read); data preserves the complete raw result, all content blocks (including non-text image / audio / resource) and newer MCP's structuredContent, for programmatic use without losing information. A tool error (isError) yields status="error"; a connection not established / already closed yields a clear error (not a bare AttributeError).
MCPTool
¶
Bases: Tool
Adapt a single MCP server tool: present it as this framework's Tool (native async, overriding arun).
__init__(client, name, description, input_schema, *, remote_name=None, origin='mcp', requires_confirmation=True, fingerprint=None, max_desc_chars=4096)
¶
Build an MCPTool wrapping one server tool.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
client
|
MCPClient
|
The owning MCPClient (which provides call_tool). |
required |
name
|
str
|
Tool display name (used by the registry / agent, with the namespace prefix). |
required |
description
|
str
|
Tool description (from the server, already sanitized, for the LLM to decide when to call). |
required |
input_schema
|
dict
|
The tool's JSON Schema (from the server's inputSchema), converted into ToolParameter. |
required |
remote_name
|
Optional[str]
|
The real tool name on the server side (used when calling); defaults to name. |
None
|
origin
|
str
|
Origin marker, stamped "mcp:{namespace}" by MCPClient (the trust root, not overridable by the tool definition). |
'mcp'
|
requires_confirmation
|
bool
|
Whether human confirmation is required (instance attribute shadowing the class attribute); default True, since untrusted remote tools require confirmation by default. |
True
|
fingerprint
|
Optional[str]
|
Tool-definition fingerprint (sha256 of remote_name + description + schema), for the app to pin and compare (tool pinning). |
None
|
max_desc_chars
|
int
|
Length limit for parameter-description sanitization (same source as client). |
4096
|
arun(parameters)
async
¶
Run natively async: forward the call to the MCP server using the remote real name (name may carry a namespace prefix and cannot be used).
get_parameters()
¶
Convert MCP's inputSchema (JSON Schema) into this framework's ToolParameter; sub-schema descriptions are likewise sanitized (strip control characters plus truncate, to prevent injection text / control characters hidden in nested descriptions), with the remaining schema fields carried over faithfully.
tool(_func=None, *, name=None, description=None, requires_confirmation=False, external_content=False, supports_parallel=False)
¶
Decorator: turns a type-annotated function into a Tool object. Supports both bare @tool and parameterized @tool(name=..., ...) forms.
The decorated name becomes a Tool directly (no longer a function), usable as Agent(tools=[f]) / registry.register(f).
Parameters / types / defaults / required-ness are inferred from the signature, the tool description comes from the first docstring line, and parameter descriptions come from Annotated or the docstring "Args:" section.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
Optional[str]
|
Tool name, defaults to the function name. |
None
|
description
|
Optional[str]
|
Tool description, defaults to the first docstring line. |
None
|
requires_confirmation
|
bool
|
Set True for high-risk actions, to pass through the confirmation gate before execution. |
False
|
external_content
|
bool
|
Set True when the result is content from an external source, to wrap it in an anti-injection guardrail before feeding it back to the model. |
False
|
supports_parallel
|
bool
|
Set True for read-only, concurrency-safe tools to allow concurrent execution with other parallelizable tools in the same turn (see the Tool class attributes). |
False
|
Example
@tool def get_weather(city: Annotated[str, "city name"], days: int = 3) -> str: """Query the weather for a city over the next few days.""" ...