---
title: "Tools reference"
description: "Parameters and defaults for the 17 Loggerhead MCP tools: nine that read, seven that change the lint rules, and one that marks a finding fixed."
source: "https://getloggerhead.com/docs/mcp-server/tools-reference/"
---

# Tools reference

> Parameters and defaults for the 17 Loggerhead MCP tools: nine that read, seven that change the lint rules, and one that marks a finding fixed.

All times use RFC 3339, for example `2026-09-08T09:00:00Z`.

Every tool that reads data takes two optional arguments. Omitted, they mean the workspace and the environment the app
shows. Call [`list_environments`](#list_environments) for the names.

| Parameter | Type | Required | Meaning |
| --- | --- | --- | --- |
| `workspace` | string | no | The workspace to read, by name or slug. |
| `environment` | string | no | The environment to read, by name, slug, or `deployment.environment.name` tag. |

## `query_logs`

Search and filter log records.

| Parameter | Type | Required | Meaning |
| --- | --- | --- | --- |
| `query` | string | no | Text to find in the log message. |
| `severity` | string | no | One of TRACE, DEBUG, INFO, WARN, ERROR, FATAL. |
| `start_time` | string | no | Start of the time range. |
| `end_time` | string | no | End of the time range. |
| `limit` | number | no | Records to return. Default 100, maximum 1000. |

Each log record carries a `resourceId`. The `resources` map of the result holds, by that id, the resource attributes
the record came with: `service.name`, `service.instance.id`, `telemetry.sdk.name`, `host.name`, and so on. One entry
per process, however many records came from it. `get_trace` returns the same map for its spans.

## `query_metrics`

Read time-series metrics.

| Parameter | Type | Required | Meaning |
| --- | --- | --- | --- |
| `name` | string | no | Metric name pattern. |
| `start_time` | string | yes | Start of the time range. |
| `end_time` | string | yes | End of the time range. |
| `percentiles` | number[] | no | Quantiles between 0 and 1, for example `[0.5, 0.95, 0.99]`. |

Loggerhead keeps a histogram as one series for each statistic, with the type `histogram`: `<name>.count`,
`<name>.sum`, and `<name>.min` and `<name>.max` when the SDK records them. Thus a name pattern such as
`http.server.request.duration` returns all the series of that histogram. Loggerhead also keeps the buckets of each
histogram point. Pass `percentiles` to get one more series per quantile and label set, named `<name>.p50`,
`<name>.p95`, `<name>.p99.9`, and so on, computed from the buckets. A summary comes back as a gauge per quantile
under its name with the label `quantile`, plus `<name>.count` and `<name>.sum`.

A series of a sum or a histogram carries its `temporality`: `cumulative` when each point is the total since the
start, or `delta` when each point is the change since the previous point. A gauge has no temporality. A delta
counter goes down by design, so do not read a fall in a delta series as a reset.

A series carries the `description` that the instrument declared, such as "Duration of HTTP server requests",
when the exporter sent one.

## `query_traces`

Search traces.

| Parameter | Type | Required | Meaning |
| --- | --- | --- | --- |
| `service_name` | string | no | Filter by service. |
| `operation_name` | string | no | Filter by span name. |
| `start_time` | string | no | Start of the time range. |
| `end_time` | string | no | End of the time range. |
| `min_duration_ms` | number | no | Only traces at least this long. |
| `limit` | number | no | Traces to return. Default 100. |

## `get_trace`

Read one trace. The result holds every span of the trace with its timing, its status, and its attributes. Each span also carries its `events` and its `links`. An event is a point inside the span with a name, a timestamp, and attributes; an SDK records an exception as an event named `exception` with `exception.type`, `exception.message`, and `exception.stacktrace`. A link points at a span in this trace or in another trace, for example the producer of the message that a consumer span handles.

The reason of a failed span is also in its attributes. `otel.status_description` holds the status message, and `exception.type`, `exception.message`, and `exception.stacktrace` hold the last exception that the span recorded.

| Parameter | Type | Required | Meaning |
| --- | --- | --- | --- |
| `trace_id` | string | yes | The trace ID. |

The result also holds `exemplars`: the metric samples an SDK took inside this trace, each with the metric name,
the point labels, the sampled value, and the span.

## `list_environments`

List every workspace on this Mac with its environments. The tool has no parameters. It returns this JSON object.

| Field | Type | Meaning |
| --- | --- | --- |
| `workspaces` | array | One entry per workspace with `id`, `name`, `slug`, `grpcPort`, `httpPort`, `effectiveGrpcPort`, `effectiveHttpPort`, `current`, and `environments`. Each environment has `id`, `name`, `slug`, `kind`, `tag`, and `current`. |
| `currentWorkspace` | string | The name of the workspace the app reads. |
| `currentEnvironment` | string | The name of the environment the app reads. |

The list is the same as the Workspaces page in the app.

## `get_receiver_info`

Report the effective OTLP endpoints of the receivers. The tool has no parameters. The top-level fields describe the workspace the app reads, and `workspaces` repeats them per workspace.

| Field | Type | Meaning |
| --- | --- | --- |
| `otlpGrpcPort` | number | The effective gRPC port. Send gRPC telemetry to this port. |
| `otlpHttpPort` | number | The effective HTTP port. Send HTTP telemetry to this port. |
| `otlpGrpcConfiguredPort` | number | The gRPC port that the root asked for. |
| `otlpHttpConfiguredPort` | number | The HTTP port that the root asked for. |
| `otlpGrpcPortConflict` | boolean | `true` when the gRPC port was busy and the root moved to another port. |
| `otlpHttpPortConflict` | boolean | `true` when the HTTP port was busy and the root moved to another port. |
| `grpcEndpoint` | string | The gRPC address, for example `http://127.0.0.1:4317`. |
| `httpEndpoint` | string | The HTTP address, for example `http://127.0.0.1:4318`. |
| `workspaces` | array | One entry per workspace with `workspace` (the name) and the same port fields. Each workspace has its own port pair. |

Call this tool before you configure an OTLP exporter. Do not assume the default ports. See [Ports and the effective port](/docs/getting-started/ports-and-the-effective-port/).

## `query_improvements`

List the telemetry-quality findings that the Linting page shows. Every parameter is optional. With no parameters the tool returns every finding.

| Parameter | Type | Required | Meaning |
| --- | --- | --- | --- |
| `impact` | string | no | One of `high`, `med`, `low`. |
| `source` | string | no | One of `logs`, `metrics`, `traces`. |
| `kind` | string | no | The detector name, for example `noisy_logs`, `stale_metric`, or `suggested_alert`. |
| `include_metric_health` | boolean | no | Also return the per-metric health table. Default `false`. |

The result has these fields.

| Field | Type | Meaning |
| --- | --- | --- |
| `generatedAt` | string | When the engine built the report. |
| `windowSecs` | number | The lookback window the engine scanned, in seconds. |
| `findings` | array | The findings that match the filters. Each finding has `id`, `kind`, `impact`, `source`, `title`, `description`, `meta`, `recommendation`, `action`, `ai`, and `count`. A folded group (several findings with the same rule and shape) also has `members`, one finding per subject. |
| `counts` | object | `total`, `high`, `med`, and `low` for the findings in the result. |
| `resolved` | array | The findings that stopped firing in the last 24 hours, the latest first. Each has `id`, `kind`, `title`, `source`, `reason`, `resolvedAt`, and `lastSeen`. The `source` and `kind` filters apply to this list. The `impact` filter does not, because a resolved finding has no impact. |
| `metricHealth` | array | One row per metric with `metric`, `state` (`ok`, `stale`, `broken`), `points`, and `lastSeen`. Present only when `include_metric_health` is `true`. |

The list has only the open lint findings. It leaves out the findings that are marked as fixed or ignored, the findings that an exception of the workspace matches, and the findings of the AI analysis. Call `query_ai_findings` for the AI findings.

The engine scans the last hour again every 30 seconds. After you fix the cause and the new code runs, call `mark_finding_fixed`. Without that call, the old telemetry keeps the finding open until it ages out of the one-hour window. A finding moves to `resolved` with one of these reasons:

- `fixed`: new telemetry of that signal arrived, and the rule does not fire on it. The fix worked.
- `aged`: the window has no telemetry of that signal. The fix is not proven. Send new telemetry, for example run the code path again, then call the tool again. If the problem is still there, the finding is in `findings` again.

## `mark_finding_fixed`

Mark one finding fixed after you changed the code and the new code runs. The old records keep the last hour tripping the rule, so Loggerhead then judges the finding by the telemetry after the fix only. At each scan, every 30 seconds:

- New telemetry trips the rule: the finding is open again.
- New telemetry of its signal arrives and does not trip the rule: the finding moves to `resolved` with the reason `fixed`.
- No new telemetry arrives: the finding stays hidden.

| Parameter | Type | Required | Meaning |
| --- | --- | --- | --- |
| `finding_id` | string | yes | The id of one finding from `query_improvements`. A group id (`group:…`) is refused; mark each member. |
| `workspace` | string | no | The workspace of the finding. |
| `environment` | string | no | The environment of the finding. The state of a finding belongs to its environment. |

The result has `findingId`, `fixedAt`, and `next`, which says what the scans do. Run the code path, wait 30 seconds, then call `query_improvements`. **Mark as fixed** in the finding menu of the Linting page does the same.

When a finding is a false positive for this project, use `add_lint_exception` or `ignore_finding` with a reason.

## `list_lint_rules`

List the lint rules behind the Linting page, with the state, the thresholds, and the exceptions the app shows on the Rules tab of the Linting page. The rule settings belong to the workspace, so every environment of the workspace uses the same rules. Call it to explain why a finding fired or did not fire, and before you change a rule. Every parameter is optional.

| Parameter | Type | Required | Meaning |
| --- | --- | --- | --- |
| `kind` | string | no | Return one rule only, by its id, for example `noisy_logs`. |

The result has these fields.

| Field | Type | Meaning |
| --- | --- | --- |
| `workspace` | string | The name of the workspace the list is for. |
| `environment` | string | The name of the environment the list is for. |
| `counts` | object | `total`, `on`, `off`, and `edited` for the rules in the result. |
| `rules` | array | One entry per rule with `kind`, `name`, `signal` (`logs`, `metrics`, `traces`, `all_signals`), `description`, `enabled`, `edited`, `ignoredFindings`, `thresholds`, and `exceptions`. Each threshold has `field`, `label`, `unit` (`ratio`, `count`, `bytes`, `seconds`, `per_minute`, `list`), `value`, `default`, `edited`, and `sharedWith`, the other rules that read the same field. A `ratio` is a share between 0 and 1. Each exception has `id`, the fields it matches, `reason`, `source`, and `createdAt`. |
| `ignoredFindings` | array | The ignored findings with `findingId`, `rule`, `title`, `reason`, `source` (`mcp` or `ui`), `scope` (`workspace` or `environment`), and `until`. |
| `recentChanges` | array | The newest changes to the settings with `id`, `at`, `source`, `action`, `rule`, `summary`, `reason`, and `undone`. |
| `note` | string | How to change a rule, on every result. |

## Change the lint rules

Seven tools change the lint rules of a workspace. Every environment of the workspace (Local, Staging, Production) uses the change. Each tool needs a `reason`, and takes an optional `workspace`. The Rules tab of the Linting page shows each change with its source, its time, and its reason, and the user can undo it there. The engine applies the change on its next scan, within 30 seconds.

Fix the telemetry at the source first. Change a rule only when a finding is a false positive for this project.

| Tool | Parameters | What it does |
| --- | --- | --- |
| `set_lint_rule_enabled` | `kind`, `enabled` | Switches a rule on or off. The rule keeps its thresholds. |
| `set_lint_threshold` | `kind`, `field`, `value` | Sets one threshold. `value` is a number, or an array of names for a `list` threshold. The value must be in the range of the threshold. |
| `reset_lint_threshold` | `kind`, `field` | Puts one threshold back to its default. |
| `add_lint_exception` | `kind`, and one or more of `service_name`, `metric_name`, `attribute_key`, `operation`, `body_pattern` | Adds an exception: the findings of the rule that match every field you give do not show. `*` matches any run of characters, and the match ignores case. `body_pattern` matches any part of the log message and needs 3 characters or more. The result gives the `exceptionId`. |
| `remove_lint_exception` | `exception_id` | Removes one exception. |
| `ignore_finding` | `finding_id`, optional `until` (RFC 3339) | Ignores one finding by its id from `query_improvements`. A group id (`group:…`) is refused; ignore each member. |
| `unignore_finding` | `finding_id` | Stops the ignore of one finding. |

A value that is not valid gives a tool error that names the argument, for example `noisy_logs.noisyLogRatio must be between 0 and 1`. See [Tune the rules](/docs/telemetry-linting/tune-the-rules/).

## `query_ai_findings`

List the findings of the last AI analysis run: the findings on the **AI analysis** page. The AI analysis reads the lint report and a sample of the raw logs and spans, and finds problems that one lint rule cannot find. Every parameter is optional.

| Parameter | Type | Required | Meaning |
| --- | --- | --- | --- |
| `impact` | string | no | One of `high`, `med`, `low`. |
| `source` | string | no | One of `logs`, `metrics`, `traces`. |

The result has these fields.

| Field | Type | Meaning |
| --- | --- | --- |
| `status` | string | `ok` when the run gave findings. `unavailable` when the model did not answer. `disabled` when no AI provider is set. `not_run` when no run happened on this environment since Loggerhead started. |
| `ranAt` | string | When the run finished. Absent for `not_run`. |
| `window` | string | The window of the run: `1h` or `24h`. |
| `model` | string | The model that made the findings. |
| `message` | string | The reason for `unavailable` or `disabled`, or what to do for `not_run`. |
| `findings` | array | The findings that match the filters, the highest impact first. Each finding has the same fields as a `query_improvements` finding, with `ai` set to `true`. |
| `counts` | object | `total`, `high`, `med`, and `low` for the findings in the result. |

**The tool does not start a run.** A run can send a sample of the telemetry to a cloud model, and a cloud model can cost the user money. The user starts a run with **Run AI analysis** on the AI analysis page. The app keeps only the last run of each environment, and only until it quits. An AI finding does not clear on its own: after a fix, ask the user to run the analysis again, then call the tool again.

## Example prompts

- "Query the logs for ERROR entries in the last hour and explain what happened."
- "Find the slowest traces from the last 24 hours and name the bottleneck span."
- "Get the trace `abc123` and explain the span hierarchy."
- "Read `loggerhead://stats` and summarise what has been collected."
- "Call `get_receiver_info` and set OTEL_EXPORTER_OTLP_ENDPOINT to the gRPC address."
- "Call `query_improvements` with impact high, fix the first finding in this project, then call it again to confirm the finding is gone."
- "Call `list_environments`, then query the staging logs for ERROR entries in the last hour."
- "Call `list_lint_rules` with kind noisy_logs and explain why this finding fired against the threshold."
- "The broken_metric finding for `pool.wait_count` is 0 because no request waits. Add an exception for that metric with a reason."
- "Call `query_ai_findings`, check each finding against the logs and traces, and fix the real ones."
