Skip to main content
Glama

printf

Read-only

Format and print text using printf-style conversion specifiers. Provides precise control over padding, number formatting, and type conversion. Returns JSON by default.

Instructions

Format and print text using printf-style conversion specifiers (%s, %d, %f, etc.). Read-only, no side effects. Returns JSON with the formatted string by default; use --raw for plain output. Use for precise control over number formatting, padding, and type conversion. Not for simple echo without formatting — use 'echo'. See also 'echo'.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
encodingNoOutput encoding.utf-8
format_stringYesPrintf-style format string.
rawNoWrite formatted text without a JSON envelope.
valuesNoValues used by format conversions.

Implementation Reference

  • Main handler function for the 'printf' tool. Calls format_printf() for the formatting logic and returns result as JSON or raw bytes.
    def command_printf(args: argparse.Namespace) -> dict[str, Any] | bytes:
        output = format_printf(args.format_string, args.values)
        data = output.encode(args.encoding)
        if args.raw:
            return data
        return {
            "format": args.format_string,
            "values": args.values,
            "encoding": args.encoding,
            "bytes": len(data),
            "content": output,
        }
  • Core printf formatting implementation: parses the format string, coerces values, and applies Python %-formatting with support for format/values cycling.
    def format_printf(format_string: str, values: list[str]) -> str:
        """执行 printf 格式化,支持格式字符串循环和值循环。
    
        规则:values 数量必须是 conversions 数量的整数倍。
        """
        fmt = decode_standard_escapes(format_string)
        conversions = printf_conversions(fmt)
        if not conversions:
            if values:
                raise AgentError("invalid_input", "printf received values but the format has no conversions.")
            return fmt
        if len(values) % len(conversions) != 0:
            raise AgentError(
                "invalid_input",
                "printf values must fill the format exactly; repeat the format by passing a multiple of its conversions.",
                details={"values": len(values), "conversions_per_format": len(conversions)},
            )
        output: list[str] = []
        for start in range(0, len(values), len(conversions)):
            chunk = values[start : start + len(conversions)]
            converted = tuple(
                coerce_printf_value(value, conversion) for value, conversion in zip(chunk, conversions, strict=True)
            )
            try:
                output.append(fmt % converted)
            except (TypeError, ValueError) as exc:
                raise AgentError("invalid_input", "printf format could not be applied to the supplied values.") from exc
        return "".join(output)
  • Extracts printf conversion specifiers (diouxXeEfFgGcrsa) from a format string.
    def printf_conversions(format_string: str) -> list[str]:
        """提取 printf 格式字符串中的所有转换标识符(diouxXeEfFgGcrsa)。
    
        不支持 '*' 宽度和精度语法。
        """
        conversions: list[str] = []
        index = 0
        valid = "diouxXeEfFgGcrsa"
        while index < len(format_string):
            if format_string[index] != "%":
                index += 1
                continue
            if index + 1 < len(format_string) and format_string[index + 1] == "%":
                index += 2  # 跳过转义的 %%
                continue
            end = index + 1
            while end < len(format_string) and format_string[end] not in valid:
                if format_string[end] == "*":
                    raise AgentError("invalid_input", "printf '*' width and precision are not supported.")
                end += 1
            if end >= len(format_string):
                raise AgentError("invalid_input", "printf format contains an incomplete conversion.")
            conversions.append(format_string[end])
            index = end + 1
        return conversions
  • Coerces string values to int/float/str based on printf conversion specifier.
    def coerce_printf_value(value: str, conversion: str) -> object:
        """将字符串值转换为 printf 转换符所需类型(int/float/str)。"""
        try:
            if conversion in "diouxX":
                return int(value, 0)
            if conversion in "eEfFgG":
                return float(value)
            if conversion == "c":
                return value if len(value) == 1 else int(value, 0)
        except ValueError as exc:
            raise AgentError(
                "invalid_input",
                "printf value cannot be coerced for the requested conversion.",
                details={"value": value, "conversion": conversion},
            ) from exc
        return value
  • Registers the 'printf' subcommand with argparse, defining its format_string positional arg and --encoding/--raw flags, mapped to command_printf handler.
    p = add_subparser("printf", help="Format text with a deterministic printf-style subset.")
    p.add_argument("format_string", help="Printf-style format string.")
    p.add_argument("values", nargs="*", help="Values used by format conversions.")
    p.add_argument("--encoding", default="utf-8", help="Output encoding.")
    p.add_argument("--raw", action="store_true", help="Write formatted text without a JSON envelope.")
    p.set_defaults(func=command_printf)
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Read-only declaration matches annotation (readOnlyHint=true), and describes default JSON output vs. raw mode with --raw.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with purpose, no redundant phrases.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers key behaviors (formatting, output modes) and side effects; missing detail on encoding but schema provides it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Description adds context about printf-style behavior beyond schema; schema covers all parameters, so baseline 3 is raised to 4 for adding usage context.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool formats and prints text using printf-style specifiers, and explicitly distinguishes from echo for simple cases.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says when to use (precise formatting) and when not (simple echo), and names the alternative tool 'echo'.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/caseSHY/AI-CLI'

If you have feedback or need assistance with the MCP directory API, please join our Discord server