Log Tools

The operations tools of the platform’s pod logs: list_log_sources, search_logs and summarize_log_errors.

Each tool validates its arguments, calls smarter.apps.mcpserver.services.logs, which reads the last 72 hours of the app, the Celery workers, beat and MariaDB from Loki, and formats the lines as Markdown. Each query is structured, not LogQL, so the LLM cannot inject a query of its own.

They are staff-only tools of the MCPServer, built on StaffTool, which records every call in the audit trail. A result that quotes log lines starts with UNTRUSTED_DATA_NOTICE, because a log line can carry text that a user wrote.

Side effects: each call makes one or two HTTP GETs to Loki (in the tests, to the in-memory log service), and the audit trail’s database write. Nothing is cached.

Note

Experimental. The MCPServer was designed and coded by Claude Code (Anthropic’s Claude Opus 5.5), with Lawrence McDaniel as co-author. It is experimental, and will be documented.

class smarter.apps.mcpserver.protocol.tools.logs.ListLogSourcesTool(user)[source]

Bases: StaffTool

The list_log_sources tool: the components and pods that logged recently.

A component that is missing from the list wrote nothing in the period, which usually means that its pods are down. The pods’ names are what search_logs’ pod argument takes.

arguments_model

alias of ListLogSourcesArguments

description: ClassVar[str] = "List the components and pods that wrote to the logs in the last minutes, from the log store, which keeps 72 hours. A component that is missing has written nothing, e.g. because its pods are down. Pod names change on every deploy and restart: use them with search_logs' pod argument."

What the tool does, and when to call it.

The LLM reads it to decide which tool to call.

name: ClassVar[str] = 'list_log_sources'

The tool’s name, which the LLM calls it by, e.g. search_logs.

run(arguments)[source]

List the components and pods that wrote to the logs in the period.

Side effects: two HTTP GETs to Loki, for the values of the component and pod labels.

Parameters:

arguments (ListLogSourcesArguments) – The validated arguments.

Return type:

str

Returns:

Markdown: the components, those of COMPONENTS that wrote nothing, and the pods.

Raises:
title: ClassVar[str] = 'List log sources'

The tool’s human-readable name, which an MCP client may show, e.g. Search pod logs.

class smarter.apps.mcpserver.protocol.tools.logs.SearchLogsTool(user)[source]

Bases: StaffTool

The search_logs tool: the lines of the pod logs that match a set of filters.

The filters become a LogQuery, which the log service turns into escaped LogQL, so the LLM’s text is never run as a query.

arguments_model

alias of SearchLogsArguments

description: ClassVar[str] = "Search the logs of the platform's pods, from the log store, which keeps 72 hours. Filter by component, pod, text, a regular expression and the least severe level. Returns the newest matching lines first, each with its time (UTC), component and pod. With no filters, it returns the latest lines, like tail. To find what went wrong, start with summarize_log_errors, then search for a signature it returns."

What the tool does, and when to call it.

The LLM reads it to decide which tool to call.

name: ClassVar[str] = 'search_logs'

The tool’s name, which the LLM calls it by, e.g. search_logs.

run(arguments)[source]

Search the pod logs.

Side effects: one HTTP GET to Loki’s query_range.

Parameters:

arguments (SearchLogsArguments) – The validated arguments.

Return type:

str

Returns:

Markdown: a heading with the number of lines, then the lines in a code block, after UNTRUSTED_DATA_NOTICE, or a hint to widen the search if no line matches.

Raises:
title: ClassVar[str] = 'Search pod logs'

The tool’s human-readable name, which an MCP client may show, e.g. Search pod logs.

class smarter.apps.mcpserver.protocol.tools.logs.SummarizeLogErrorsTool(user)[source]

Bases: StaffTool

The summarize_log_errors tool: the errors of the pod logs, grouped by their signature.

It reads up to SUMMARY_LINES warning and error lines, and groups them with error_groups(), so that the LLM sees each problem once, with how often it happened, rather than thousands of lines.

arguments_model

alias of SummarizeLogErrorsArguments

description: ClassVar[str] = "Summarize the errors, and optionally the warnings, in the platform's pod logs over the last minutes: the lines are grouped by component, level and signature (the message without its numbers, ids and quoted values), and each group has its count, its pods, when it was first and last seen, and its latest line. Call it first when a user reports errors, slowness or an outage, then use search_logs for the lines around a group."

What the tool does, and when to call it.

The LLM reads it to decide which tool to call.

name: ClassVar[str] = 'summarize_log_errors'

The tool’s name, which the LLM calls it by, e.g. search_logs.

run(arguments)[source]

Group the errors, and optionally the warnings, of the period.

Side effects: one HTTP GET to Loki’s query_range.

Parameters:

arguments (SummarizeLogErrorsArguments) – The validated arguments.

Return type:

str

Returns:

Markdown: a heading with the number of lines, then one section for each group, the most frequent first, after UNTRUSTED_DATA_NOTICE, or a heading that says there were none.

Raises:
title: ClassVar[str] = 'Summarize log errors'

The tool’s human-readable name, which an MCP client may show, e.g. Search pod logs.