Tool formatting¶
Tool-related utilities for Klea
File: klea_utils/tools.py
Copyright 2026 Ankur Sinha Author: Ankur Sinha <sanjay DOT ankur AT gmail DOT com>
- klea_utils.tools.build_tool_description(t: mcp.types.Tool) tuple[str, str][source]¶
Build the full and compact LLM-facing descriptions for an MCP tool.
Returns a
(full, short)tuple.klea_utils.mcp.schemas.ToolInfostores both: the full form (heading + docstring + compact parameter list) is what the tool picker needs to emit calls, while the short form (heading + docstring only) is for planner-style nodes that reason about which tools exist without the argument detail (tiered disclosure).Klea expects MCP tool descriptions to follow the docstring-first convention (see
docs/concepts/mcp.rst, “Tool description length and style”): the LLM-facing description is the opening text block of the function docstring, written as a one-sentence summary followed by “Use when:” / “Do not use for:” bullet sections and a single example line, bounded to roughly 100-250 tokens. Anthropic recommends at least 3-4 sentences covering what a tool does and when it should (and should not) be used; opencode keeps its tool descriptions to roughly 100-600 tokens with a one-line summary first.Parameter descriptions are given in a Google-style
Args:section that fastmcp parses into the schema, so they must not be repeated in the description. MCP servers must not set the tool description to the raw full docstring (seeneuroml_mcp.utils.register_tools), otherwise the prompt carries duplicatedArgs:/Returns:prose in both the description and the compact parameter list built here.
- klea_utils.tools.clean_tool_meta(meta: dict[str, Any] | None) dict[str, Any] | None[source]¶
Drop developer tags from tool metadata before storing it.
FastMCP populates
metawith{"fastmcp": {"tags": [...]}}; the tags are mostly developer labels (e.g.testing) that are not used by the tool picker, so they are stripped to keep stored metadata lean.
- klea_utils.tools.last_tool_error_text(tool_results: list[fastmcp.client.client.CallToolResult] | None, max_len: int = 500) str[source]¶
Return the text of the last error result in a batch, or
"".Used to give the tool picker concrete feedback when a round failed (for example an
edit_fileambiguity), so it can adjust the call instead of repeating it. Only the last error is returned: the picker retries one round at a time, so the most recent failure is the one to correct.- Parameters:
tool_results – The batch’s tool results (
Nonetreated as empty).max_len – Truncate the extracted text to this many characters.
- Returns:
The final error result’s textual content, or
""if none.
- klea_utils.tools.textualize_tool_results(tool_results: list[fastmcp.client.client.CallToolResult], max_len_per_tool: int | None = None, include_header: bool = True) str[source]¶
Format tool call results as LLM-ready text for use in prompt context.
Tool return values are typically JSON-structured data (dicts, lists) which LLMs handle naturally. We wrap them in markdown code blocks for clear separation from surrounding prompt text.
- Parameters:
tool_results – List of tool call results
max_len_per_tool – If set, truncate each tool’s textual content to this many characters (per-tool cap, not total). Ensures a large first result doesn’t starve later tools’ outputs.
include_header – When
True(default) emit the batch header (## Tool Results) and a### Result i/nlabel per result. SetFalseto render the bare content of a single result, e.g. when a caller supplies its own per-result heading.
- Returns:
Formatted string suitable for inclusion in an LLM prompt
- klea_utils.tools.tool_call_errors(tool_calls: Sequence[Any] | None, tool_results: Sequence[fastmcp.client.client.CallToolResult] | None, *, max_value_chars: int = 300, max_error_chars: int = 300, max_total_chars: int = 2000) str[source]¶
Render the failed calls in a tool batch as a compact LLM-facing digest.
CallToolResultdoes not carry the tool name or arguments, so calls and results are aligned by index.dispatch_tool_callsguarantees one result per input call in input order; a missing call is rendered as an unknown tool. Only the latest batch is described (the caller passes the currenttool_calls/tool_results).Values are included only for arguments with an explicitly path/URI-like name (plus the picker’s declared
paths), and are redacted/truncated. Arbitrary free-text arguments (file contents, edit strings, code, shell commands) are deliberately omitted: this is an allowlist, not a guess at whether a string “looks like” a path.- Parameters:
tool_calls – Calls that produced tool_results, in dispatch order.
tool_results – Results for the batch.
max_value_chars – Per-argument value cap.
max_error_chars – Per-error text cap.
max_total_chars – Total digest cap.
- Returns:
One line per failed call, or
""when nothing failed.