Skip to content

Python API

Everything below is importable from toolproof and covered by the versioning policy. Other modules are internal and may change in any release.

from toolproof import (
    CallResult,
    Config,
    ConfigError,
    McpServer,
    RunReport,
    ServerConfig,
    ServerError,
    load_config,
    run_config,
    run_config_async,
)

Running a config

load_config(path) -> Config

Reads and validates a toolproof.yaml. Relative paths in it resolve from the file's folder, and ${VAR} in the server section is expanded. Raises ConfigError with a readable message if the file is missing or invalid.

run_config(config, phases=None) -> RunReport

Runs a config and returns the results. phases is any of "checks", "tests", "evals", "bench", "fuzz". By default it runs what toolproof run would: checks and tests, plus evals, bench and fuzz if the config has those sections. Phases always run in that order.

run_config starts its own event loop. From async code, use await run_config_async(config, phases) instead.

from toolproof import load_config, run_config

report = run_config(load_config("toolproof.yaml"), phases=["tests"])
for test in report.tests:
    print(test.name, "ok" if test.passed else test.failures)
assert report.passed

RunReport

Attribute Type Description
passed bool True if there's no connection error, no failing check, test, benchmark or fuzz finding.
error str or None Why the server couldn't be reached, with its stderr.
phases list of str The phases that ran.
server_name, server_version str or None From the server's handshake.
tool_names list of str Every tool the server listed.
checks list Static check problems: tool, check, severity ("error" or "warning"), message.
tests list Test results: name, tool, passed, failures, latency_ms, attempts, result (a CallResult), server_stderr.
bench list Benchmark results: name, tool, calls, concurrency, errors, error_rate, throughput, p50_ms, p95_ms, p99_ms, mean_ms, max_ms, failures, passed.
fuzz list Fuzz results per tool: tool, calls, skipped, findings (each with kind, mode, input, detail), passed.
fuzz_seed int or None The seed the fuzz phase used.
evals object or None Eval results: provider, model, accuracy, correct, min_accuracy, passed, error, and cases (each with name, prompt, expect_tool, expect_args, picked_tool, picked_args, failures, cached, passed).
duration_s float Wall-clock time of the run.

Talking to a server directly

McpServer(config, base_dir=None)

An async context manager holding one connection. For a stdio server it starts the process; leaving the block stops it.

import anyio

from toolproof import McpServer, ServerConfig


async def main() -> None:
    config = ServerConfig(command=["python", "server.py"])
    async with McpServer(config) as server:
        tools = await server.list_tools()
        result = await server.call("get_weather", {"city": "Toronto"}, timeout_s=5)
        print([t.name for t in tools], result.data)


anyio.run(main)
Method Description
await call(tool, arguments=None, timeout_s=None) Call a tool and return a CallResult. Never raises for tool errors, timeouts or a lost connection.
await list_tools() All tools, following pagination.
await server_info() Name, version, tools, resources and prompts.
await is_alive(timeout_s=5) Whether the server still answers.
await reconnect() Start a fresh connection (and process, for stdio). Safe to call from any task.
stderr_tail(lines=20) The last lines a stdio server wrote to stderr.

base_dir is the folder relative paths in command and cwd resolve from. It defaults to the current directory.

Raises ServerError if the server can't be started or the handshake fails. The message includes the server's stderr.

ServerConfig

The server section of a config, as a pydantic model: command, url, env, headers, cwd, startup_timeout_s. See Configuration. ${VAR} is only expanded by load_config, not when you build a ServerConfig in code.

CallResult

Attribute Type Description
tool, arguments What was called.
is_error bool The tool reported an error, the server returned a JSON-RPC error, the call timed out, or the connection was lost.
text str Text content blocks joined with newlines.
structured any Structured content, if the tool returned any.
data any structured, or text parsed as JSON, or None.
latency_ms float Time the call took.
transport_error str or None Set when no result came back: a timeout or a lost connection.
timed_out bool The call hit its timeout.
protocol_error bool The server answered with a JSON-RPC error instead of a tool result.
error_code int or None The JSON-RPC error code when protocol_error is set.

Exceptions

Exception Raised when
ConfigError A config file is missing, isn't valid YAML, fails validation, or uses an unset ${VAR}.
ServerError The server can't be started or reached.