Skip to main content
Glama
ssimonsen0202

berserk-mcp

berserk-mcp

CI

berserk-mcp is an MCP server. It lets an LLM answer Berserk observability questions. The LLM calls tools for this. The LLM does not write KQL by hand.

Why this matters: A raw query language makes a model guess. It guesses wrong table names, wrong field names, and broken aggregations. Each wrong guess costs you a retry. Every tool in berserk-mcp wraps one verified Kusto/KQL query. The model picks an intent — for example top_cpu, errors_by_service, or sre_host_headroom. The query itself stays fixed. This fixed-query design is the core idea. It lets even small or cheap models answer observability questions reliably.

  • Works with Claude Desktop, Claude Code, and any MCP client. By default, berserk-mcp speaks MCP protocol version 2025-06-18 over stdio (newline-delimited JSON-RPC 2.0). It implements every required method — initialize, notifications/initialized, ping, tools/list, tools/call — with strict envelope validation and adversarial regression tests. See Connect it to a client for claude_desktop_config.json and claude mcp add recipes.

  • MCP compatibility baseline. The stable default remains 2025-06-18 stdio. Additive 2026-07-28 MCP features are available only when explicitly enabled with BERSERK_MCP_ENABLE_2026_07_28=1, so existing clients keep their legacy response shapes. See MCP 2026-07-28 adaptation baseline.

  • Optional HTTP transport is closed by default. stdio remains the default. HTTP opens no listener unless explicitly enabled, defaults to loopback, and fails closed for remote bind unless auth, Host allowlisting, and CIDR allowlisting are configured. See MCP HTTP transport and reverse proxy deployment and .env.example.

  • Zero dependencies. berserk-mcp uses only the Python standard library. You do not pip install anything beyond the package itself. (The optional LLM parser factory uses urllib. It still adds no third-party dependency.)

  • Small and auditable. berserk-mcp is standard-library-only. Its focused modules cover the MCP server, parser generation, Claude analytics, AI FinOps, KQL validation, schema snapshots, secret redaction, and ingestion advice. You can read, audit, and vendor each module without pulling in a framework.

  • Cross-platform. berserk-mcp runs anywhere the bzrk CLI runs, including Windows.

  • Safe by construction. berserk-mcp uses fixed queries. It validates input on every free-text tool. It never calls shell=True. The Berserk token never touches this code.

  • Self-extending (new in 1.7). An optional parser factory detects new sources arriving in Berserk. It uses an LLM to author, execute-verify, and save KQL "query packs" for each new source. The design follows Microsoft Sentinel's ASIM parser AI agent. It tries cheap providers first, enforces hard runaway fail-safes, and never lets a generated query overwrite a human one.

  • Knowledge-artifact lifecycle bridge. An optional CanonLoom bridge exposes a separate, self-hosted service that turns a source URL into a validated, versioned skill artifact. This covers source acquisition, relevance scoring, artifact-diff comparison, generation, structural/injection validation, and git-committed promotion. berserk-mcp only speaks to CanonLoom's HTTP API. None of CanonLoom's own dependencies (FastAPI, Anthropic, pygit2, and its stricter Python 3.14+ floor) touch berserk-mcp's own zero-dependency footprint.

⚠️ Disclaimer — please read

berserk-mcp is an unofficial, community-built project. The Berserk project and its maintainers do not sponsor, endorse, support, or affiliate with it. berserk-mcp talks to Berserk only through the public bzrk CLI. It uses no internal API and no reverse engineering.

berserk-mcp is provided as-is, with no warranty and no liability. This covers any use, outcome, downtime, data loss, or cost (see LICENSE). You run berserk-mcp at your own risk against your own infrastructure. Pointing it at a production Berserk is your decision.

For bugs, feature requests, and questions about this server: open an issue in this repository. For questions about Berserk itself: contact the Berserk project, not this repository.

Related MCP server: Spyglass AI MCP Server

Release history

Current version: 1.28.0. This is a bullet-point overview, most recent first — full detail for each notable release lives in docs/releases/.

  • v1.28.0 (2026-09-03) — Model-behavior monitoring: model_drift_check and model_drift_history classify a canaried model's tool-routing accuracy over time against a calibrated noise band, plus a --drift-report CLI that alerts on sustained degradation. Two rounds of independent Codex review, both fully re-verified by direct execution before and after each fix. See details.

  • v1.27.0 (2026-08-28) — Five security fixes from an independent Codex review: KQL validator bypasses, unfenced telemetry attributes, a gap in the injection delimiter, an OAuth-header redirect leak, and a bug that read the text "false" as true. Also adds investigate_error_rate (issue #24): a fixed, step-by-step tool that walks a decision tree to find the cause of an elevated error rate, scoped to the SRE/Ops lane. See details.

  • v1.26.0 (2026-08-24) — Untrusted-data fencing, tool tiers, just-in-time tool discovery (find_tool, 92% measured token reduction), a live quota-window check (claude_quota_status), an agent parameter on the base Claude Code query tools for querying other ingested agents' data, and a schema-fetcher bug fix (a failed backend call was silently cached as a "fresh" schema). See details.

  • v1.25.1 (2026-08-11) — Performance bugfixes for shipped KQL: selective service filtering, shallower unfiltered schema discovery, CI cost guardrails, and validator-derived query-budget headroom. See details.

  • CanonLoom bridge (2026-08-03, commit 033d855, "CLP-9 CanonLoom MCP tool bridge") — five new tools (canonloom_run_pipeline, canonloom_list_artifacts, canonloom_get_artifact, canonloom_freshness_report, canonloom_run_history) bridging to a separately-run canonloom-server. Landed after v1.24.0 with no dedicated release-notes entry; see CanonLoom bridge below.

  • v1.24.0 (2026-07-31) — MCP 2026-07-28 adaptation and safe-default HTTP transport: gated modern discovery, modern result envelopes, structured reporting output, private cache hints, input-required guidance, in-memory task lifecycle support, and a closed-by-default HTTP listener with auth, Host, CIDR, request-size, concurrency, and reverse-proxy guidance. See details.

  • v1.23.0 (2026-07-27) — Security remediation Phase 3: generated-content sanitization, per-deployment HMAC owner pseudonyms, spreadsheet-safe CSV, model-facing fence hardening, mandatory Discord egress redaction, scrubbed public deployment examples, and honest fixed-window Grafana dashboards. See details.

  • v1.22.0 (2026-07-27) — Security remediation Phases 0–2: execution-boundary KQL guards, bounded bzrk output, trusted binary resolution, deterministic FinOps redaction, shared cross-platform private stores, hardened HTTP for every outbound caller, strict primer configuration, and offline regression coverage. See details.

Older releases (v1.2.0 through v1.21.1 — enterprise Claude AI FinOps, schema-grounded KQL validation, distributed-trace tools, agent-log analytics, fleet-friendly worker tuning, the parser factory's early fail-safes, role profiles, and the initial release) are in docs/releases/, one file per version.

Why this exists

Berserk is a self-hosted observability engine. It uses the OTEL standard, and it needs no fixed schema. It handles data at petabyte scale. Berserk stores logs, metrics, and traces sent over OTLP. You query this data with a Kusto-style language (KQL), through the bzrk CLI or the web UI. Berserk is headless by design — built for agents that ask questions, not for dashboards. Berserk gives you the storage and the query engine. It still assumes the asker, human or agent, already knows KQL.

The gap. LLMs handle raw query languages badly. Point a model at bzrk directly, and it invents table names, mistypes fields, and wastes tokens on retries. Two fixes seemed obvious at first: paste the schema into the prompt, or give the model examples of KQL. Neither fix worked. The model kept guessing. Writing the queries by hand, in advance, did work.

What berserk-mcp adds. berserk-mcp sits in front of Berserk as a translation layer. It turns observability intents into MCP tools — for example top_cpu, errors_by_service, sre_service_health. Each tool runs one query. berserk-mcp has already checked that query against the live schema. The model never writes KQL. It only picks an intent and a time window. berserk-mcp does not replace Berserk's storage, query engine, or UI. It makes them usable by an agent, and reliable even on small or cheap models.

berserk-mcp also adds three layers that Berserk does not have on its own:

  1. Role lanes — each agent sees only the tools its job needs

  2. Discovery queue and auto-KQL worker — new telemetry sources onboard with no manual query-writing

  3. Amendments log — every save_query write is tracked, so a worker can post changelogs and keep the query store auditable

Approach

Result

Berserk web UI / bzrk CLI

Good for a human who knows KQL. An agent cannot use it well.

Point an LLM at the raw CLI and schema docs

Unreliable. The model guesses table and field names, and pays for retries.

A generic "text-to-KQL" MCP

Still writes queries. Same guessing problem, one layer up.

berserk-mcp

Fixed, checked queries. The model only picks a tool and a time window. It never writes KQL. See Choosing a model for the measured reliability floor by model size.

What this adds vs. default Berserk

Berserk is a strong observability backend for humans, on its own. berserk-mcp does not replace any part of it. berserk-mcp sits next to Berserk and adds a surface built for agents.

As of v1.1.0, Berserk ships its own agent too: a Chat tab in the web UI, with its own tool-calling loop, doc search, and model picker. This is a different kind of agent from berserk-mcp, not a smaller version of it. It writes its own free-form queries at chat time. berserk-mcp never does this. Every question maps to one fixed, checked query. The model only selects it. This matters in practice. We tested Berserk's native Chat against our own deployment. It could not finish a basic question. It never picked a valid database, so every list_tables/query call it made failed. Full detail is in the issue we filed.

Capability

Default Berserk

berserk-mcp

Ingest OTLP logs / metrics / traces

✅ core

reuses

KQL query engine + storage

✅ core

reuses (read-only)

Web UI + bzrk CLI for humans

✅ core

reuses

Token auth, profiles

✅ core

reuses (bzrk holds the token)

MCP surface for LLMs / agents

General-purpose chat agent (web UI Chat tab, v1.1.0)

✅ — authors its own free-form queries at chat time; broken on our reference deployment as of v1.1.0 (see above)

not applicable — berserk-mcp never authors free-form KQL

Common questions answered without authoring KQL

requires correct Kusto → small models fail

✅ fixed verified tools

Role-aware tool filtering (SRE / SOC / Claude / Ops lanes)

BERSERK_MCP_ROLE env var

Role primers injected at initialize

✅ KQL rules, thresholds, routing guidance per lane

Telemetry-shape discovery

partial (.show tables)

list_metrics · discover_schema · container_hosts

Custom-query persistence as named, reusable tools

UI has a Query Library. Berserk documents no API or CLI verb to create, list, or share a saved query programmatically

save_query (verify-before-persist) → run_saved, agent-readable

Automated source onboarding

request_discovery → worker → saved query, no KQL authoring needed

LLM parser factory — detect a new source, auto-author + verify a KQL query pack

detect_new_sources · generate_parser · run_discovery_worker · review_generated (ASIM-agent-style; see below)

Query changelog / amendments log

✅ every save_query write tracked; --worker posts a Discord diff if alerting is configured

Two-lane cost model (cheap default · on-demand @deep)

✅ tool descriptions + annotations make this safe

KQL-injection guards on free-text inputs

n/a (humans)

✅ service-name allowlist · claude_search reject-list

Trace/span analysis — find slow/failed traces, reconstruct a span tree with correlated logs

trace_find_slow · trace_find_errors · trace_analyze (v1.14.0; see Trace tools)

Model-behavior monitoring — detect provider changes and routing-quality regressions via scored canary and fingerprints

model_drift_check · model_drift_history (v1.28.0; see Model-behavior monitoring tools)

Knowledge-artifact lifecycle pipeline (source URL → validated skill artifact)

canonloom_run_pipeline · canonloom_list_artifacts · canonloom_get_artifact · canonloom_freshness_report · canonloom_run_history, bridged to a separate canonloom-server (see CanonLoom bridge)

Why this complements Berserk's native MCP (not competes with it)

Berserk ships its own MCP server, bzrk mcp. It is a raw query console. It runs query/start_query sessions. It offers table and database discovery, and get_docs for KQL reference. Its design assumes the agent writes its own KQL. This console suits a skilled human KQL author well. It is the wrong everyday tool for most models. They guess table names, get aggregations wrong, and waste tokens on retries.

berserk-mcp is a fixed layer on top of the same backend. The model picks a checked intent. berserk-mcp does the math. The answer comes back as a conclusion — a verdict, a baseline change, a cost trend — not a row dump.

Use the native MCP server when a skilled KQL author drives the session. Use berserk-mcp when you want any model, including small local ones, to answer reliably. Both servers can run side by side in the same client, with no conflict.

Sovereign and defense deployments (fully local stack)

Every layer of this stack can run on hardware you own. No data needs to leave your network. This suits sovereignty-constrained, defense, and air-gapped environments:

  • Berserk is self-hosted. Telemetry never leaves your network.

  • berserk-mcp uses only the Python standard library. It has no third-party packages and sends no telemetry of its own. It never contacts an outside service on its own. You can read and check its five small files in an afternoon.

  • The LLM layer can run locally too. The parser factory's provider ladder speaks the OpenAI-compatible API. Any local open-weight model works as the hermes endpoint — through Ollama, llama.cpp, vLLM, or LM Studio. You do not need a frontier API. The fixed-query design also lowers the skill the model needs. It only picks a tool and a time window. It never writes KQL.

  • Defense-in-depth on the egress path. Even when you configure an LLM endpoint, it receives only structural telemetry — key names, shapes, redacted excerpts. It never receives raw values. The endpoint URL must match an allowed scheme, and only an operator can set it.

What we have actually checked about self-hosted model use — not just claimed. This corrects earlier guidance in this section. That guidance claimed "small local models route reliably." We measured this. The claim did not hold.

How we tested this, and what we found

We ran a real eval. We did not rely on a published benchmark. Local models ran through Ollama, on real hardware. Hosted models ran through OpenRouter, the same way a production deployment would call them. Every model answered the same 41 test cases, from evals/router_cases.jsonl, against berserk-mcp's own real tool schema — 69 tools, the schema size at test time. We measured four things per model: tool-selection accuracy, argument accuracy, latency (median and p95), and real billed cost per call. Cost came from the API's own reported figure, not a sticker-price guess. Test date: 2026-08-22/23. Full method, raw findings, and later re-checks: docs/model-routing-cost-validation-2026-08-23.md.

Model

Tool-selection accuracy

Argument accuracy

Latency (median / p95)

Real cost per call

deepseek/deepseek-chat

93%

98%

4.2s / 4.7s

$0.0114 (never caches)

stealth/ox-alpha

93%

93%

7.3s / 20.8s

$0 (promotional pricing, not durable)

deepseek/deepseek-v4-flash

88%

93%

3.6s / 12.7s

$0.0003 (caches 5.5x)

mistralai/mistral-saba

83%

90%

0.76s / 1.5s

$0.00056 (caches 10x)

mistralai/mistral-small-3.2-24b-instruct (open-weight, self-hostable)

78%

90%

1.2s / 3.2s

n/a — local candidate

mistralai/mistral-nemo

63%

85%

1.6s / 4.0s

$0.0005

mock keyword-match baseline

65.9%

Qwen2.5:7b (local)

7%

63%

free / local

Llama3.1:8b (local)

5%

66%

free / local

This table is what the claims below rest on:

  • 7-8B local models do not work well enough. Qwen2.5:7b and Llama3.1:8b scored 7% and 5% tool-selection accuracy — far below the keyword-match baseline of 65.9%. Public tool-calling benchmarks (BFCL) rank these model families well. But those benchmarks test a much smaller tool count. They do not predict how a model performs at this schema size (see the now-outdated shortlist in evals/model-eval-plan.md).

  • The measured reliability floor is the ~24B parameter class. mistral-small-3.2-24b-instruct (Apache 2.0, on Hugging Face, about 55GB of GPU RAM at bf16) is the only model in this test that is both open-weight and genuinely self-hostable, and it clears the baseline. mistral-saba scores close behind it, but is proprietary and API-only — not a self-hosting candidate despite the similar accuracy.

  • Run it role-scoped. The configuration matters more than the model. Re-measured on 2026-09-03 against the current 51-case set, the same model scores very differently depending on which role lane it runs in:

    Lane

    Tools

    Tool-selection accuracy

    ops

    23

    100%

    sre

    32

    96%

    soc

    31

    95%

    claude

    46

    89%

    all (no role set)

    74

    80%

    The penalty at all is not raw tool count. It is cross-lane competitor contamination: a claude_* prompt loses to a similarly-worded tool from the SRE or core lane (for example claude_search losing to search). Setting BERSERK_MCP_ROLE removes those competitors and recovers the accuracy. Full data and method: docs/mistral-small-optimization-plan-2026-09-03.md.

  • Still unverified: local behavior. Every number above comes from the same OpenRouter-hosted test as the other candidates, not from a real local deployment. Speed and behavior at the intended quantization, on real hardware, have not been checked. Note also that the tool schema alone is roughly 8K estimated tokens at ops and 12K at sre, so the 8k-context local target named in the dev brief does not fit any role lane — see the plan document above.

  • mistral-nemo, one size class down at about 12B, scored below the keyword-match baseline. Do not assume a smaller model works well anywhere in this range.

  • Bottom line for a sovereign deployment today: plan for a model of 24B parameters or more, on an open license, with a GPU — not a small model. A fully local setup with a genuinely small (7-8B) first tier is not yet a checked, working setup for this server's tool count.

Bridging Berserk's two use cases: AI Ops without leaving the sovereign boundary

Berserk's own positioning covers two cases. AI Ops says any MCP-aware agent can query your telemetry directly. Defence says nothing should leave the boundary you control. Taken on their own, these two cases conflict. The AI Ops case assumes a capable model that writes its own KQL and reasons over raw results. But a frontier model is itself an outside dependency, and the Defence case rules that out. Berserk solves this for the data: self-hosted, WORM storage, no foreign jurisdiction. It does not solve this for the reasoning layer on top of the data.

berserk-mcp closes that gap. The model only ever picks a tool and a time window. It never writes KQL and never sees raw values. So a small, local, open-weight model can drive the whole interaction reliably. The result is the AI Ops experience: agents ask questions instead of humans reading dashboards. The whole agent loop stays inside the sovereign boundary — not just the telemetry store.

This is not a hypothetical case. One real deployment uses a Discord-facing local agent to answer on-call questions against Berserk. The agent logs every tool call. It logs every full prompt and reply too. It sends all of this back into Berserk itself, as structured, queryable records: model name, redacted arguments, redacted results, and session ID. Berserk's AI Ops page describes this same idea in its Ethira governance case study: a durable, checkable record of what the agent actually did. Here, it runs end-to-end against berserk-mcp, not a custom-built integration. The claude_* tool family (claude_cost_report, claude_token_burn, claude_workflow_insights, and others) gives the same token-use and BI story that page describes. These tools already work, and already answer real queries.

The target setup is two-tier, fully local. A local open-weight model at the measured reliability floor (~24B class — see above) handles the everyday calls. The goal is 80% or more of all interactions handled this way. The model escalates to a larger, local open-weight model only for @deep work: parser generation, deep-dive synthesis, incident write-ups. "Small" here means the smaller of the two local tiers, not a 7-8B model — those were tested, and they are not reliable enough to anchor either tier. We built and tested the escalation logic itself — a rule that decides when to route up — against a cloud-hosted small/deep pair, in evals/escalation_policy.py. We still need to pick and check the real local model for each tier, on real hardware. The original measurement plan is in evals/model-eval-plan.md (Part 3). Read its Part 1 benchmark shortlist with caution — it predates the real test above, and its picks did not hold up at this server's real tool count.


Architecture

How the lanes talk to each other and to Berserk

flowchart LR
  classDef user      fill:#0d1117,stroke:#58a6ff,color:#c9d1d9
  classDef mcp       fill:#161b22,stroke:#8b949e,color:#c9d1d9
  classDef security  fill:#3a0d0d,stroke:#f85149,color:#c9d1d9
  classDef berserk   fill:#1d1d3a,stroke:#a371f7,color:#c9d1d9

  User([User / agent · Claude Code, Claude Desktop, etc.]):::user

  subgraph M["berserk-mcp (stdio · zero-dep Python)"]
    direction TB
    Tools["Tools\nquery · discover · learn"]:::mcp
    Redact["Secret / PII filter\nruns on every response"]:::security
    Tools --> Redact
  end

  subgraph T["Token boundary"]
    direction TB
    Bzrk["bzrk CLI\nholds the bearer token"]:::berserk
  end

  subgraph B["Your Berserk instance"]
    direction TB
    Gw[("KQL engine + storage")]:::berserk
  end

  User -- "ask a question" --> Tools
  Tools -. "argv, no shell" .-> Bzrk
  Bzrk -- "read-only, bearer auth" --> Gw
  Redact -- "filtered answer" --> User

Two things worth knowing about this diagram:

  1. The bearer token never enters this code. bzrk owns the token in its own configuration. berserk-mcp invokes it with an argv list: no shell, no token in berserk-mcp process memory, no token in berserk-mcp logs. Private-file permissions are platform-specific — see Security.

  2. Every tool response passes through the secret/PII filter before reaching a model. It fails closed: if the redaction mode is unset, it defaults to the safest setting (redact) rather than passing text through unfiltered.

This diagram covers the core, always-on path. berserk-mcp also bridges optionally to CanonLoom — a separate project, reached over plain HTTP, purely opt-in via CANONLOOM_SERVER_URL. Every canonloom_* tool checks that variable at call time and returns a clear configuration error if it's unset; nothing in the diagram above requires it to be running.

This is the high-level picture. The cheap/deep model split, the learning-loop cache, the discovery worker, role filtering, and transport options are covered elsewhere in this README and in the tool descriptions themselves.

Optional: two-lane model split, OpenRouter-backed

The diagram above shows one model talking to berserk-mcp. In practice most deployments split that into two lanes, and either lane can be pointed at OpenRouter instead of calling Anthropic/OpenAI directly.

flowchart TB
  classDef cheap  fill:#0d3a1d,stroke:#3fb950,color:#c9d1d9
  classDef deep   fill:#3a1d0d,stroke:#d29922,color:#c9d1d9
  classDef mcp    fill:#161b22,stroke:#8b949e,color:#c9d1d9
  classDef router fill:#1d1d3a,stroke:#a371f7,color:#c9d1d9

  subgraph H["MCP host"]
    direction TB
    Cheap["⚡ default lane\npicks tools + time windows\ncheap/local model"]:::cheap
    Deep["🧠 @deep lane\nauthors + verifies KQL\ngenerate_parser · discover-worker"]:::deep
  end

  Cheap -- "tools/call, role-filtered" --> M["berserk-mcp"]:::mcp
  Deep -- "generate_parser / run_discovery_worker" --> M

  subgraph OR["Optional: OpenRouter"]
    direction TB
    RouterNode["any model on OpenRouter's catalog"]:::router
  end

  M -. "BERSERK_LLM_HERMES_URL points here instead of\nAnthropic/OpenAI directly, first in BERSERK_LLM_LADDER" .-> OR

How it actually works: berserk-mcp's own LLM calls — used only by generate_parser and the discovery worker to author and verify KQL, never by the query path in the diagram above — go through a provider ladder (BERSERK_LLM_LADDER, default hermes,openai,anthropic) that tries each configured provider in order. hermes isn't a specific vendor; it's any OpenAI-compatible /chat/completions endpoint set via BERSERK_LLM_HERMES_URL — pointing it at https://openrouter.ai/api/v1/chat/completions with an OpenRouter API key routes that lane through whatever model you choose on OpenRouter instead of paying Anthropic or OpenAI directly. This is independent of the MCP host's own cheap/deep model choice, which is set by whatever client you're running berserk-mcp inside of (Claude Code, Claude Desktop, etc.), not by berserk-mcp itself.

Example ingestion topology (not shown in the diagram)

The diagram above covers the query path: how an agent asks questions. The ingestion path is separate. A typical deployment runs a lightweight journal forwarder on each monitored host. It tails explicitly selected services and ships OTLP log payloads through a local collector into the Berserk gateway. Each service uses its own resource['service.name'], so list_services, logs_for_service, and search filter by the workload rather than the forwarding mechanism. Keep real host and service inventories in private deployment documentation.


Role lanes

Set BERSERK_MCP_ROLE to scope what an agent sees. The filter applies at the MCP protocol level. An unrelated tool never appears in tools/list, so it cannot be called by accident and cannot be injected into context.

Role

BERSERK_MCP_ROLE

Gets

Typical agent

SRE

sre

Core tools + SRE tools (error rate, host headroom, ingest health, service health, top errors)

On-call Slack bot, editor assistant

SOC

soc

Core tools + SOC tools (high-severity logs, log spike, new services, repeated errors, incident timeline)

Security monitoring agent

Claude Code

claude

Core tools + Claude telemetry, AI spend, feature economics, data quality, and governed harness recommendations

Developer workflow and AI FinOps assistant

Ops

ops

All tools (full visibility)

Operator shell, admin scripts

Default

all (or unset)

All tools

Development, evaluation

Role primers

When a lane connects, berserk-mcp injects a markdown primer into the MCP initialize response, before the standard instructions. Each primer carries:

  • Tool routing table — which tool to reach for first, for each intent

  • Escalation thresholds — for example CPU load > 2.0, memory > 85%, error rate > 10/min, ingest lag > 30 s

  • KQL authoring rules — time window defaults, field name conventions, aggregation patterns

  • Discovery flow guidance — when to call request_discovery instead of authoring ad-hoc KQL

This means the agent config needs no prompt engineering. The routing knowledge travels with berserk-mcp.

Primers live in primers/<role>.md, next to the server file. An explicit BERSERK_MCP_PRIMERS_DIR must be absolute and contain a readable <role>.md for the active lane; otherwise startup fails with a configuration error. The all role receives no primer and routes from tool descriptions directly.


Tools

Core tools (all lanes)

Tool

What it answers

list_containers

Containers currently sending metrics (with sample counts).

top_cpu

Containers ranked by CPU %. Use for container-specific questions; for host CPU use host_cpu.

top_memory

Containers ranked by memory (MB). Use for container-specific questions; for host memory use host_memory.

errors_by_service

ERROR-level log counts grouped by service.

list_services

All services/sources, with log vs metric breakdown.

list_hosts

All hosts reporting telemetry, by record count.

host_cpu

Per-host CPU (1-minute load average). Default for ambiguous whole-machine CPU questions.

host_memory

Per-host memory used (GB). Default for ambiguous whole-machine memory questions.

container_hosts

Which host/VM each container runs on (join key for container↔host questions).

logs_for_service

Recent log lines for one service.

schema

Live tables + column schema introspection.

list_metrics

Every metric name being ingested, with counts (discovery).

discover_schema

Field metadata (type, cardinality, representative values) via Berserk's native fieldstats, plus a structural presence sample, to learn an unknown source without exporting raw telemetry (v1.17.0; previously bag_keys-based).

validate_kql

Validate custom KQL before saving or running it. Static mode checks syntax shape, schema fields, bounds, and cost-risk without executing the query; live mode is opt-in and returns a runtime receipt when enabled.

bzrk_query_perf

Berserk query engine latency percentiles (p50/p95/p99 in µs).

search

Run arbitrary KQL (escape hatch). Static validation runs before execution in the default warn mode. Save the result with save_query once it works. Fields are nested resource/attributes, not flat columns — for example resource['service.name'], not service_name. Call discover_schema first if you don't know the field names for a source.

Every query tool takes an optional since argument ("15m ago", "1h ago", "2d ago", …) with a sensible per-tool default.

Per-host vs. per-container: host_cpu and host_memory report per host. top_cpu and top_memory report per container. The tool descriptions cross-reference each other, so the model picks the right one. For an ambiguous whole-machine question — for example "what's hammering the server?" — always prefer the host tools.

SRE tools (sre lane only)

Tool

What it answers

sre_error_rate

Error log events by service grouped per minute — "is the error rate climbing?"

investigate_error_rate

Fixed decision-tree root-cause walk for an elevated error rate — errors_by_service → correlated log-spike → failing traces, one hop per call.

sre_host_headroom

CPU load and memory by host — "which VM is saturated?"

sre_ingest_health

Berserk ingest lag and dropped data — "is observability lagging?"

sre_service_health

Full health summary for one named service: event volume, error count, log/metric split, last seen.

sre_top_error_messages

Most-repeated error messages by service — "what error should I investigate first?"

detect_anomalies

Statistical service-volume anomaly detection using zero-filled series.

forecast_capacity

Native trend fit for an allowlisted host gauge; refuses weak forecasts.

SOC tools (soc lane only)

Tool

What it answers

soc_high_severity_logs

Recent CRITICAL/FATAL log lines with service and message text.

soc_log_spike

Services with the largest minute-level log bursts — "anything spiking?"

soc_new_services

Recently first-seen services and sources — "what is new?"

soc_repeated_errors

Error messages that repeat persistently — probes, loops, stuck processes.

soc_timeline

Full incident timeline for one named service: timestamps, severity, metric names, message snippets.

detect_anomalies

Statistical service-volume anomaly detection using zero-filled series.

find_similar

Meaning-based log search when semantic indexing is enabled.

scan_secrets

Aggregate potential-secret counts by service/type with first-seen timestamps. Values are never returned.

Claude Code tools (claude lane only)

If you ship Claude Code session logs into Berserk (service name claude-code), these tools mine that data. See docs/claude-code.md for the pipeline.

Tool

What it answers

claude_recent

Recent Claude Code events — type, role, model, tool names, error flag.

claude_sessions

Sessions rollup — event counts, first/last seen, assistant turns, tool turns, error count.

claude_tools

Tool-use histogram — how many times each tool (Bash, Edit, Read, …) was called.

claude_errors

Failed tool results with message snippets.

claude_search

Full-text search across Claude Code message and tool bodies.

claude_quota_status

Live quota-window check: reads Anthropic's account-usage endpoint when available (macOS only), falling back to a log-derived token estimate over the trailing window otherwise. Doesn't require the ingestion daemon running.

claude_loop_check

Flags sessions that repeat the same tool/target, retry the same error, or oscillate between calls.

claude_model_fit

Heuristic model-tier fit: frontier model on trivial work, or cheap model on complex/repetitive work. Not a billing statement.

claude_token_burn

Token burn per session and progress unit, using exact usage attributes when present and a labeled estimate otherwise.

claude_cost_report

Multi-day cost report: per-day burn with exact/estimated labels, per-model split, optional per-project attribution from file paths, and a burn-growing/flat/declining trend verdict backed by Berserk's native series_fit_line (reports R², v1.17.0).

claude_session_deep_dive

One session's timeline: contiguous tool phases with error counts, activity gaps over 5 minutes, cumulative burn, and a loop verdict.

claude_workflow_insights

Cross-session patterns: most common tool sequences, error hotspots by tool+target, top-decile burn-per-target sessions.

claude_spend_overview

Token classes, public API-equivalent spend, cache ratio, trends, attribution, and pricing coverage grouped by business or technical dimension.

claude_feature_cost

Planned/actual developer hours and AI budget/spend, completion forecast, repositories, agents, harnesses, and delivery outcomes for one feature.

claude_project_economics

Feature and repository economics within one project, including unattributed spend and data-quality coverage.

claude_efficiency_insights

Evidence for expensive models, operations, retries, loops, cache misses, context growth, and agent fan-out.

claude_harness_recommendations

Deterministic, stable-ID harness amendments with confidence, risk, validation window, and rollback criteria.

claude_record_recommendation_decision

Append-only approval, rejection, or deferral audit record. Owners use a deployment-scoped HMAC pseudonym; rationale is stored as a hash.

claude_optimization_impact

Matched before/after harness comparison with keep, rollback, no-change, or insufficient-evidence verdict.

claude_management_report

Portfolio, project, or feature summary as readable Markdown plus versioned structured JSON.

claude_generate_dashboard

Privacy-safe Markdown or self-contained HTML snapshot beneath the configured report directory.

claude_recent, claude_sessions, claude_tools, claude_errors, and claude_search accept an optional agent parameter (default claude-code) to query a different ingested agent's data instead — for example agent="codex-cli". Every other tool in this table is still Claude-Code-specific.

Agent-log intelligence

A read-only analytics layer for the claude lane (v1.12.0; see release notes):

  • claude_loop_check groups tool calls by session. It reports the repetition ratio, the top repeated call, the error-retry count, and a verdict: healthy, some-repetition, or likely-looping.

  • claude_model_fit maps model names to a coarse tier (frontier, mid, cheap). It compares that tier to a complexity proxy built from tool count, errors, duration, and loop signals.

  • claude_token_burn uses claude.tokens_input and claude.tokens_output when present. When they are absent, it falls back per session to body characters / 4. It computes burn per distinct tool plus inferred file target, and highlights top-decile burn. Every result labels its source as exact or estimated.

  • --agent-report runs all three checks headlessly. It exits non-zero when a session is likely looping or underpowered, so cron or systemd can pipe the stdout summary to an alert transport. "high-burn" alone is a relative marker — it is always present, because it is a top-decile ranking — so it is intentionally excluded from the alert threshold:

berserk-mcp --agent-report --since "6h ago"
berserk-mcp --agent-report --agent-report-mode weekly --agent-report-json --since "7d ago"

Phase J deep analytics (v1.15.0; see release notes): claude_cost_report, claude_session_deep_dive, and claude_workflow_insights extend this layer with multi-day cost trends, per-session timeline drilldowns, and cross-session workflow patterns. Per-project cost attribution infers a project name from file-target paths: it uses the directory before the first marker segment (src, tests, lib, pkg). Override this with BERSERK_MCP_PROJECT_MARKERS.

claude_token_burn, claude_loop_check, and claude_model_fit parse real bzrk --json output directly — _json_records() unwraps Tables[0].rows against Tables[0].schema.columns, matching each row's positional array to its column order. claude.tokens_input and claude.tokens_output are the real attribute names used for exact token counts. See the v1.14.1 release notes for the silent-failure bug this fixed and the live-verification story behind it.

Secret detection and output redaction

A stdlib-only secret scanner at the MCP output boundary (v1.12.0; see release notes). BERSERK_MCP_REDACT controls how every tools/call result is handled:

  • redact (default since F-009, 2026-07-20) replaces detected values with typed placeholders, such as [REDACTED:aws_key].

  • flag leaves the result intact and prepends a warning when a secret is detected. This is an explicit opt-in away from the safer default. berserk-mcp logs a startup warning to stderr when you set this.

  • off disables output scanning entirely. This is also an explicit opt-in, with a startup warning.

An unrecognized BERSERK_MCP_REDACT value fails closed to redact, the strictest mode, never to a weaker one.

The scanner recognizes common cloud/provider credentials, private keys, JWTs, bearer tokens, and generic password/token assignments. High-entropy matching is opt-in, because it is false-positive-prone. Email, IP, and Luhn-validated credit-card checks are each individually selectable. scan_secrets audits recent log bodies but returns only aggregate counts and timestamps; it never returns the matched values. This protects MCP output only. You must still remove secrets already stored in Berserk at ingest, and rotate any exposed credentials.

Learning loop tools (all lanes)

Tool

What it answers / does

list_saved

List saved queries visible to the current role. Check here before authoring new KQL.

run_saved

Run a saved query by name — deterministic, no KQL authoring.

save_query

Verify a KQL query runs, then persist it under a name (with optional role tag). Logs every write to the amendments log.

Ingestion advisor

suggest_ingestion is an all-lane read-only tool (v1.12.0; see release notes), backed by the editable ingestion_catalog.json knowledge base. The tool recommends concrete sources, explains why each source matters, names an ingestion mechanism, and labels its maturity: turnkey, collector-receiver, bridge-required, or manual.

Seeded use cases:

  • sre/aws-cloud-native

  • sre/azure

  • sre/onprem-ad-health

  • soc/endpoint-identity

  • change-management/ansible

  • scom

Set check_gap=true to compare service and metric hints with the live Berserk inventory. Each recommendation is marked present or missing, with the matching signal or the exact ingestion action. For example:

suggest_ingestion role_or_usecase=sre/onprem-ad-health check_gap=true

The AD path recommends Security, System, and Directory Service channels through the OTel Collector windowseventlog receiver. The Ansible path uses the community.general.opentelemetry callback. SCOM is explicitly bridge-required: it needs a read-only REST/API or warehouse-SQL-to-OTLP bridge. The advisor does not claim a native SCOM OTel receiver exists.

Discovery tools (all lanes)

Tool

What it does

request_discovery

Queue a newly-added service or metric for automated onboarding. Validates the source exists in Berserk before accepting.

discovery_status

List pending and completed discovery jobs.

Just-in-time tool discovery (find_tool, opt-in)

Not to be confused with the telemetry-source discovery tools above — this is discovery over berserk-mcp's own tool catalog.

Tool

What it does

find_tool

Search-by-intent over the full tool catalog. Returns the best-matching candidates with their complete inputSchema inline, so a model can call a tool it was never shown up front.

Set BERSERK_MCP_DISCOVERY=1 to switch from listing the full tool catalog up front to exposing 8 fixed anchor tools plus find_tool as the entry point for everything else (v1.26.0, issue #14). Measured against a real MCP handshake: the full schema costs ~17,560 tokens; discovery mode costs ~1,386 — a 92% reduction. A recall-gate test (tests/test_tool_discovery.py) requires every shipped tool to be reachable by at least one realistic phrasing before it ships; current measured recall is 100% across 210 phrasings covering all 70 tools. Off by default — every tool stays directly listed unless you opt in. See Choosing a model for why this matters most for smaller models.

Trace tools (all lanes)

Tool

What it answers

trace_find_slow

Highest-duration root spans in the time window — "what's slow?" Entry point before trace_analyze.

trace_find_errors

Spans whose status indicates an error — "which requests failed?" Entry point before trace_analyze.

trace_analyze

Full breakdown of one trace by trace_id: every span in time order, plus correlated log lines sharing the same trace_id.

Distributed-trace analysis (v1.14.0; see release notes), following this table's <signal>_name field convention (metric_name for metrics, body and severity_text for logs). We ported this feature from a separate TypeScript MCP prototype that explored the same problem space. These tools are verified against a real Berserk cluster whose own internal services are self-instrumented — service=query, service=gateway, and service=ingest spans are real trace/span data, not synthetic test fixtures (see Live-verified, not just unit-tested).

Two design points worth knowing:

  1. duration is a dynamic-typed column. Berserk's KQL engine rejects sort by duration directly. trace_find_slow casts it with toint(duration) before sorting.

  2. Not every row sharing a trace_id is a span. Other correlated telemetry — for example a log row — can carry the same trace_id/span_id with a null span_name. trace_analyze filters to isnotnull(span_name), and sorts by start_time so parent spans order correctly before their children.

(Both were live bugs found while verifying this feature against a real cluster outage — see the release notes for the full story.)

Native analytics and graceful degradation

detect_anomalies and forecast_capacity (v1.18.0; see release notes) use Berserk's native series functions, returning compact arrays instead of exporting raw event windows. Forecast responses include R² and slope; trends with R² below 0.6 or a non-positive slope are explicitly reported as not forecastable rather than inventing a ceiling date.

find_similar depends on semantic indexing and the similarto parser feature. On clusters where that feature is unavailable, the tool does not fail open or pretend exact matching is semantic — it explains the limitation and directs the caller to search with an exact has term.

Model-behavior monitoring tools (all lanes)

Monitor whether a canaried model still performs as well as when it was chosen. Set BERSERK_MCP_CANARY_MODELS (a comma-separated list of model IDs) to enable the feature. The canary runs daily (via --canary-run), scores models against a frozen case set, and computes a behavioral fingerprint to catch provider changes.

Tool

What it answers

model_drift_check

Check whether any canaried model has drifted. Returns stable, degrading, step-change, or insufficient-data per model, with provider fingerprint status. Measures tool-routing quality only, not prose or reasoning quality.

model_drift_history

Score and fingerprint history for one canaried model over time. Use after model_drift_check flags a drift verdict to investigate.

Design notes:

  • Frozen case set. The canary reads BERSERK_MCP_CANARY_CASES (default: evals/canary_cases.jsonl), a separate, immutable test set. The main router cases (evals/router_cases.jsonl) grow over time; a frozen set prevents score drops from conflating "we added harder cases" with "the model got worse".

  • Version is self-maintaining. The case-set version is a hash of its contents. Editing the file automatically changes the version, stopping cross-version comparison. No discipline required.

  • Behavioral fingerprints. Two independent signals catch provider changes: a metadata fingerprint (hashes the provider's declared model entry — context length, pricing, version) and a behavioral fingerprint (hashes temperature-0 completions for a fixed prompt set). A changed fingerprint is a signal to investigate, never proof the provider swapped the model — hardware nondeterminism and batching can change output without a model change.

  • Noise band is calibrated, not a permanent constant. The 0.02 (2-point) noise band comes from 5 live canary runs against deepseek-v4-flash on 2026-09-01 (mean tool_accuracy 0.9514, stdev 0.0049, range 0.0139 — full run-by-run data in docs/model-routing-cost-validation-2026-08-23.md). It's a starting point from one model's one calibration sweep — re-run the calibration if the case set changes size materially, or once real production history accumulates to compare against.

  • Failed runs are not zeros. A failed canary run is recorded as a failure, never scored as zero. This prevents a provider outage from looking like a catastrophic quality drop.

  • Cost reminder. Canary runs cost real money — and more than a quick single-case check suggests. A full run over the 48-case set at the default BERSERK_MCP_CANARY_REPEATS=3 measured ~$0.08 and 7.5–8.5 minutes per model, per run (deepseek-v4-flash, 2026-09-01). Set BERSERK_MCP_CANARY_REPEATS to tune spend, and budget wall-clock time accordingly if running several models sequentially.


Cost & BI reporting

berserk-mcp also ships a separate cost and attribution layer. It runs through CLI flags and a wrapper binary (berserk-claude), not tools/call. Native Claude Code OpenTelemetry is the preferred input. Reports normalize input, output, cache-read, cache-creation, long-context, and chargeable server-tool usage into one versioned, public-API-equivalent cost. This is not an invoice. An unknown model stays unpriced rather than getting a guessed rate. You can launch Claude with governed work context, so telemetry attributes to a feature without exposing prompts or source code. You import planning and actuals through a neutral CSV/NDJSON contract. You export management-ready BI datasets and dashboards from the same model. Generated outputs contain aggregates and coverage metadata only — never prompts, code, or cleartext owner IDs.

Full CLI reference (flags, business-data record shapes, export/dashboard format, privacy/permission details): docs/cost-and-bi-reporting.md. If nothing is showing up in the claude_* tools yet, start with docs/otel-setup.md — it covers which features need OTel-ingested Claude Code data at all, the two ways to get it in, and what each collection path does and doesn't attribute automatically (repository and branch land automatically; pull-request numbers currently need a manual correlation step).


Self-extending: discovery and learning

The fixed tools cover known telemetry. For data with no tool yet — a log source you just started shipping — a two-stage loop extends berserk-mcp without hand-editing code. The cheap lane stays deterministic throughout.

Stage 1: Discovery queue

QUEUE    request_discovery(service="haproxy")   →  validates source, queues job
WORKER   discover-worker drains queue at 06:00  →  authors KQL by role/kind
SAVE     save_query (verify-before-persist)      →  permanent, named query
REUSE    run_saved("sre_haproxy_service")        →  cheap model, free, forever

request_discovery does one check before it accepts a job: it calls list_services (or list_metrics) to confirm the source is actually visible in Berserk. An unknown source is rejected with a clear error, so the queue never fills with phantom jobs.

The discover-worker (berserk-mcp --worker, invoked from a daily cron entry — there is no separate discover-worker.py file) drains the queue:

  • Chooses the right KQL template per role. sre gets a health summary, soc gets an incident timeline, claude gets a health rollup, and metric kind gets a drilldown aggregation.

  • Calls save_query to verify and persist the result.

  • Updates known_sources.json so the same source is never re-queued.

  • Posts a summary of completed and failed jobs to Discord, if BERSERK_DISCORD_ALERT_SECRET is configured (see below). This step is skipped when there is nothing noteworthy — no new sources found and no jobs drained — so a quiet day does not generate a daily ping.

Stage 2: @deep amendments and improvements

A capable model (@deep, a scheduled agent, or an operator) may improve or correct an existing query via save_query. The generation pipeline may also save a new query. Either way, berserk-mcp:

  1. Tags the entry action=generated (pipeline-authored), action=updated (a human save to an existing name), or action=created (a human save to a new name).

  2. Appends a timestamped entry to amendments_log.json, with the name, description, KQL preview, role, and action.

  3. Reads and formats a changelog on the next --worker run, if Discord alerting is configured (🤖 generated, ✏️ updated, ✨ created). It clears the log only if the post is confirmed — a transient Discord outage leaves the entries intact for the next run, instead of losing them.

This means the query store is auditable. Once Discord alerting is configured, every improvement made by an autonomous agent can be surfaced in a Discord channel automatically, with no operator action.

Configuring Discord alerts

berserk-mcp does not talk to Discord's API directly. No bot token and no webhook secret lives in this process. Instead, berserk-mcp posts to a small local HTTP bridge (loopback by default) that already knows how to reach your Discord channel:

Variable

Default

Purpose

BERSERK_DISCORD_ALERT_URL

http://127.0.0.1:8765/alert

The bridge's alert endpoint.

BERSERK_DISCORD_ALERT_SECRET

unset

Shared secret sent as X-Auth-Token. Alerting is entirely off unless you set this — no default secret, no silent posting.

The bridge must accept POST <url> with header X-Auth-Token: <secret> and JSON body {"text": "..."}, and return 2xx on success. If the bridge runs on a different host than berserk-mcp's --worker cron job, the same loopback-only-by-default policy applies as for the LLM endpoint. Set BERSERK_LLM_ALLOW_PLAINTEXT_REMOTE=1 to allow a non-loopback http:// URL, or point at an https:// bridge instead. Prefer HTTPS for any bridge that is not bound to loopback; the shared secret is sent as an HTTP header and should not cross an unencrypted network. Alerts are sent only from the headless --worker CLI path. Interactive MCP tool calls (for example run_discovery_worker) already surface their result directly to the caller and never post to Discord — this avoids duplicate, noisy notifications.

The intended division of labour is cost-efficient:

  • A capable model does the rare, hard part. It discovers the new shape, authors and verifies the query, and calls save_query. Trigger it two ways: on a schedule (a daily job that checks the discovery queue), or on demand ("I just added HAProxy to Berserk — add support").

  • The cheap model uses the result. Every saved query is reusable for free, deterministically, via run_saved. Authoring KQL is the one thing small models handle badly, so this step is gated behind the stronger model. save_query verifies the query runs before persisting it, as a guardrail.

This design scales because learned queries live behind list_saved/run_saved, not as first-class tools. You can learn dozens of new sources without growing the routing surface that keeps the cheap model reliable.


Parser factory: LLM-generated query packs

When a new source starts shipping to Berserk with no tool for it yet, the parser factory automates what a human would otherwise do by hand: discover_schema, hand-write KQL, save_query. Following the design of Microsoft's ASIM parser AI agent for Sentinel, it samples the source, generates KQL, validates by executing it, refines on failure (capped at 5 cycles per provider), and persists only the verified survivors as a reusable query pack — 2-4 saved queries per source. Tries cheap/local providers first, has hard runaway fail-safes (per-run caps on both queuing and generation), and never lets a generated query silently overwrite a human-saved one.

Tools: detect_new_sources, generate_parser, run_discovery_worker, review_generated. Full pipeline mapping, configuration reference, headless/cron mode, and safety details: docs/parser-factory.md.


CanonLoom: knowledge-artifact lifecycle bridge

The parser factory (above) turns new telemetry sources into verified KQL. CanonLoom solves the analogous problem for knowledge sources: turning a source URL into a validated, versioned skill artifact through a five-phase pipeline (CLP-1 through CLP-5) with a hard validation gate before anything is trusted. CanonLoom is a separate project, not part of berserk-mcp — it ships its own HTTP API server (canonloom-server) and knowledge repository; berserk-mcp only bridges to that API via five tools, with zero shared dependencies. Run berserk-mcp with no canonloom-server anywhere and everything else works exactly as documented above; only the canonloom_* tools return a clear setup error instead of a result.

Tools: canonloom_run_pipeline, canonloom_list_artifacts, canonloom_get_artifact, canonloom_freshness_report, canonloom_run_history. Deployment diagram, pipeline-phase reference, configuration, and worked examples: docs/canonloom-bridge.md.


Worked examples

Concrete prompts you can paste into any MCP-aware client. Each example shows the natural-language question, the tools the model calls, and the kind of answer you get. All of these work on the cheap default lane — no frontier model required.

ChatOps: "any errors in the last hour?" (SRE lane)

Have there been any errors in the last hour, and from which service?

Calls errors_by_service (since="1h ago"). The model replies with the per-service error count, or "no errors recorded" when the result is empty. On the SRE lane, the primer nudges the model toward sre_error_rate for a time-series view when the count is above threshold.

On-call triage: "is api-gateway healthy?" (SRE lane)

Is api-gateway healthy? What's the error rate and when was it last seen?

Calls sre_service_health(service="api-gateway"). It returns total events, error count, log/metric split, and the last-seen timestamp in one round trip. If the error count is high, the primer's threshold guidance nudges the model to follow up with sre_top_error_messages.

SOC investigation: "what happened on otel-collector?" (SOC lane)

Reconstruct what happened with otel-collector over the last 2 hours.

Calls soc_timeline(service="otel-collector", since="2h ago"). It returns timestamped events with severity, metric names, and message snippets, ordered newest-first — a ready-made incident narrative, with no KQL authoring.

Security sweep: "anything new or anomalous?" (SOC lane)

Anything unusual in the last 30 minutes? Spikes, new sources, repeated errors?

Calls soc_log_spike, soc_new_services, and soc_repeated_errors in one pass. The SOC primer tells the model to scan all three before summarising.

Developer workflow: "what tools is Claude Code using?" (Claude lane)

What tools has Claude Code used most this week, and were there any errors?

Calls claude_tools(since="7d ago") and claude_errors. This only works if you ship Claude Code session logs into Berserk via an OTLP forwarder — see docs/claude-code.md.

Onboarding a new source

I just added HAProxy logs to Berserk. Integrate it.

(With SOUL.md or a system prompt configured.) The agent calls request_discovery(service="haproxy", role_hint="sre"). The discovery worker runs overnight. It authors and saves sre_haproxy_service. The next morning, run_saved answers HAProxy questions on the cheap lane, permanently.

Autonomous daily health digest (cron / scheduled agent)

You are an on-call assistant. Use the Berserk MCP to:
1) Check load per host (host_cpu, host_memory) over the last 6 hours.
2) Count errors per service over the last 24 hours (errors_by_service).
3) List the top 5 noisiest containers (top_memory).
Write a 10-line digest, flag anything anomalous, and stop.

This is deterministic enough to run unattended overnight on gpt-4.1-mini or a self-hosted ≥24B model — a 7-8B local model is not reliable enough for this (see Choosing a model). Wire it to a cron job — the answer is short and parseable.


Requirements

  • Python 3.9+. (Python 3.8 reached upstream end-of-life on 2024-10-07 and is no longer a supported floor.)

  • The bzrk CLI, installed and authenticated (bzrk -P <profile> search "..." must work). The bearer token lives in bzrk's own config. berserk-mcp never reads or stores it.

  • (Optional) A running canonloom-server instance, only if you use the canonloom_* tools — a separate project with its own, stricter requirements; berserk-mcp only calls its HTTP API and adds nothing to berserk-mcp's own dependency footprint. Setup: canonloom's README.

Install

berserk-mcp is not yet published to PyPI. Install from source:

git clone https://github.com/ssimonsen0202/berserk_mcp
cd berserk_mcp
pip install .

pip install berserk-mcp, pipx install berserk-mcp, and uvx berserk-mcp will work once this project is published under that name. Do not run them yet: the name berserk-mcp is currently unclaimed on PyPI, so those commands would silently succeed against whatever unrelated or malicious package claims it first.

berserk-mcp uses only the Python standard library. It has no third-party runtime dependencies. Installation must include the accompanying local modules declared in pyproject.toml plus packaged data (primers/, ingestion_catalog.json). Use pip install . or a built wheel. Do not copy berserk_mcp.py alone.

Authenticate to bzrk

berserk-mcp does not talk to Berserk directly. It wraps the bzrk CLI. Authentication is bzrk's job, not berserk-mcp's. The Berserk bearer token lives only in bzrk's own config. berserk-mcp never reads it, stores it, forwards it, or logs it.

Recommended one-time setup:

# 1. Log in to Berserk with the profile name you'll use from the MCP.
bzrk login          # follow the prompt for endpoint + token
# or
bzrk -P prod login  # log in to a specific named profile

# 2. Verify auth works with the same profile the MCP will use.
bzrk -P local search "default | take 1" --since "1h ago"

# 3. Point the MCP at that profile (or leave BZRK_PROFILE unset for `local`).
export BZRK_PROFILE=local

Profiles. Berserk uses named profiles (local, prod, staging, and others). You can point the MCP at a different tenant by changing one env var. berserk-mcp reads BZRK_PROFILE and passes it to every bzrk invocation as -P <profile>. In claude_desktop_config.json this looks like "env": {"BZRK_PROFILE": "prod"} — see Connect it to a client below.

Non-default bzrk binary. If bzrk is not on $PATH — for example, if it is Homebrew-installed or lives in a per-repo .venv — set BZRK_BIN to the full path. berserk-mcp invokes bzrk with an argument list, never through a shell, so quoting is not a concern. On Windows, use an absolute path to the trusted executable. A bare name that resolves inside the MCP client's current working directory is rejected to prevent executable planting.

Auth failures at runtime. If bzrk returns an authentication error — bad token, expired session, wrong profile — berserk-mcp returns this constant string:

bzrk authentication failed; run `bzrk login` and retry

For authentication failures, berserk-mcp never propagates raw bzrk stderr, tokens, or tenant identifiers to the caller. Other backend diagnostics can be returned to the MCP caller, but they are bounded and pass through output redaction; see Security for the full rationale.

Full bzrk auth options (SSO, service accounts, per-profile config) are out of scope for this README. See the official Berserk CLI docs at https://docs.bzrk.dev. berserk-mcp only requires that bzrk -P <profile> search "..." succeeds, from the same shell environment berserk-mcp will run in.

Fleet-friendly operation

When many MCP instances share one Berserk cluster, berserk-mcp limits the load each instance contributes (v1.18.0; see release notes):

  • Worker mode adds randomized startup jitter, preventing synchronized cron bursts.

  • Interactive calls use a separate per-tool budget and return an actionable narrower-window message when the budget is exceeded.

  • Identical timeout retries are suppressed briefly to prevent retry storms.

  • Allowlisted read-only rollups use a short in-process cache. Cached results are marked (cached, <age>s old); mutation, discovery, generation, and arbitrary-search tools are never cached.

These controls are per-process and can be disabled or tuned with the environment variables in the configuration table below. Each default is a measured value, not an arbitrary guess — see the v1.18.0 release notes for the evaluation evidence behind each number.

Configure

All configuration is via environment variables, all optional — covering query/worker tuning, KQL validation policy, redaction and pseudonymization, BI/report paths, OTLP export, and the optional HTTP transport. Full table and defaults: Configuration reference.

Parser-factory (LLM parser generation) has its own env vars — see Parser factory above.

The CanonLoom bridge has its own two env vars (CANONLOOM_SERVER_URL, CANONLOOM_API_KEY) — see CanonLoom bridge below.

Transport security guidance

Every non-loopback endpoint that carries a token, API key, or telemetry payload (Hermes, Discord alerts, OTLP export, the optional HTTP MCP transport, and the Berserk cluster endpoint itself) needs HTTPS/TLS, and code enforcement already covers the endpoints berserk-mcp owns — schemes allowlisted, embedded credentials and control characters rejected, no redirect-following, bounded response bodies, and HTTPS required for remote OTLP. Full per-endpoint guidance: Transport security and TLS guidance.

Connect it to a client

Compatibility. berserk-mcp implements MCP protocol version 2025-06-18 as a stdio server (newline-delimited JSON-RPC 2.0). All 63 registered tools appear in the tools/list handshake, and each can be invoked via tools/call. The stdio handshake path — including every required lifecycle method (initialize, notifications/initialized, ping, tools/list, tools/call) — has been externally exercised by two independent scanners: Cisco AI Defense mcp-scanner and MCP-Shield. Both scanners enumerated the full tool surface with no protocol errors. Every method has adversarial regression coverage in the test suite. Any client that speaks the same protocol version — Claude Desktop, Claude Code, and third-party MCP clients — can drive berserk-mcp with no server-side changes.

Claude Desktop

Add to claude_desktop_config.json (Settings → Developer → Edit Config):

{
  "mcpServers": {
    "berserk-q": {
      "command": "berserk-mcp",
      "env": {
        "BZRK_PROFILE": "local",
        "BERSERK_MCP_ROLE": "sre"
      }
    }
  }
}

If you didn't pip install it, point at the file instead:

{
  "mcpServers": {
    "berserk-q": {
      "command": "python",
      "args": ["/absolute/path/to/berserk_mcp.py"],
      "env": {
        "BZRK_PROFILE": "local",
        "BERSERK_MCP_ROLE": "sre"
      }
    }
  }
}

Claude Code

claude mcp add berserk-q -- berserk-mcp
# or from source:
claude mcp add berserk-q -- python /absolute/path/to/berserk_mcp.py

Set the role in your shell or .env:

BERSERK_MCP_ROLE=sre claude mcp add berserk-q -- berserk-mcp

Any MCP client

Launch berserk-mcp (or python berserk_mcp.py) as a stdio MCP server. It speaks newline-delimited JSON-RPC 2.0 over stdio, MCP protocol version 2025-06-18.

Auditing tool calls from an agent-framework client

Some MCP hosts keep a full per-run session transcript on disk, including every tool call's arguments and result. One example is an agent framework named "Hermes." (This Hermes is unrelated to this repo's own BERSERK_LLM_HERMES_URL/HERMES_API_KEY provider settings, described above — those configure berserk-mcp's own upstream chat-completions client for generation, not an MCP host.)

scripts/hermes_tool_call_log.py walks that transcript store. It emits one full-fidelity JSON line per tool call — model, arguments, result, untruncated — filterable by MCP server name. Use it to confirm which model actually drove a tool call, or pipe it into jq for ad-hoc auditing. MCP's stdio transport does not expose the caller's model identity to the server, so this script fills that gap without berserk-mcp needing to know it.

Choosing a model

The fixed-query design's core idea is that the model never writes KQL. It only picks a tool and a time window. This lowers the skill the model needs: instead of "can author correct Kusto," it only needs "can do basic tool-calling." That is what makes cheap and local models viable in principle. But the real floor is higher than earlier guidance here claimed. A real-model eval sweep (2026-08-22/23; 8 models, 2 local via Ollama and 6 cloud via OpenRouter; full methodology and per-model table in docs/model-routing-cost-validation-2026-08-23.md) found:

  • 7-8B local models are not viable against the full tool schema. Qwen2.5:7b and Llama3.1:8b scored 5-7% tool-selection accuracy — well below a dumb keyword-matching baseline (66%). The previous recommendation here ("7B is the sweet spot") was wrong; corrected in v1.26.0.

  • The measured reliability floor is the ~24B parameter class. mistral-saba (24B) reached 83% tool-selection accuracy. One size class down (mistral-nemo, ~12B) fell below the keyword baseline.

  • Best measured performer: deepseek-chat (93% tool-selection, 98% argument accuracy). Best cost/performance: deepseek-v4-flash (88% tool-selection, ~38x cheaper per call than deepseek-chat thanks to real prompt caching — verified against actual billed usage.cost, not sticker price). Caveat: tool_choice: "required" silently disables that caching; use "auto" to keep it.

If a small local model is a hard requirement, use just-in-time tool discovery — cutting the schema from 69 tools to 8 is a real, measured accuracy lever (92% token reduction), though it did not close the gap to zero for the 7-8B models in this sweep. For unattended local deployments, prefer a ≥24B model with a GPU over a smaller one.

  • Cheap API. deepseek-v4-flash, gpt-4.1-mini, Claude Haiku, or Gemini Flash give strong tool use at a fraction of frontier cost. Good for latency-sensitive ChatOps replies.

  • Frontier models are rarely necessary. Save them for open-ended investigations that use search and save_query, or as an escalation tier for cases a cheaper model's own routing confidence flags as uncertain (see evals/escalation_policy.py).

The biggest reliability lever, regardless of model, is the tool descriptions. They are written to be narrow and unambiguous, so a small model routes correctly. Keep new tool descriptions that way.

Security

berserk-mcp applies defense in depth across the execution boundary, KQL validation, secret/PII redaction, generation-pipeline resource bounds, concurrency-safe store writes, role-visibility enforcement, and outbound-HTTP hardening. Each control has a name and an adversarial regression test. See Security controls for the full list of about 30 controls, plus the audit history: a hand audit, a differential re-review, and an external scanner pass across three tools. One open finding as of 2026-08-29: the HTTP transport's DNS-rebinding protection (BERSERK_MCP_HTTP_ALLOWED_HOSTS) is opt-in rather than defaulted on for a loopback bind — see docs/mcp-conformance.md and issue #84.

The server has also been run against the official MCP conformance test suite — results, including that one finding, in docs/mcp-conformance.md.

To report a vulnerability, see SECURITY.md.

Wrong-answer containment

berserk-mcp groups its controls against a confident false negative under one name. A confident false negative is an agent reporting a clean bill of health when a query silently matched zero rows, went stale, or the tool refused to run a broken query. Most open-source observability MCP implementations state hallucination defenses like rate limiting, query timeouts, and read-only execution. These protect backend stability. Few address this query-result failure mode — the one that actually pages someone at 4am.

Six controls make this up, each with a locking test: field-access guidance for nested OTLP attributes, full-text search term-boundary guidance, KQL validation that rejects blockers before execution, schema-drift warnings on saved queries, a result envelope that tells apart the bare (no rows) sentinel, and untrusted-data fencing against a smuggled instruction in a log line. See docs/wrong-answer-containment.md for full detail, known limits, and the regression test for each.

Testing

python -m pytest tests/ -q
# stdlib unittest is also supported:
python3 -m unittest discover -s tests

The tests stub the bzrk CLI. They verify: KQL content and lock strings, default time windows, role isolation (which tools appear in which lane), injection guards, since validation, tool annotations, JSON-RPC protocol, the learning loop, discovery-queue deduplication, and amendments-log behavior. The parser-factory suite additionally fakes the LLM HTTP layer, to verify the escalation ladder, source profiling, new-source/drift detection, generation, validation, refinement, and headless worker mode. The agent-analytics suite verifies loop detection, model-fit classification, MCP dispatch, and the headless --agent-report path.

Live-verified, not just unit-tested

The stubbed suite proves berserk-mcp's logic is internally consistent. It does not prove the KQL executes correctly against a real cluster. So every SRE and SOC tool also runs through berserk-mcp's real dispatch path against a live Berserk deployment, as part of the release process. This live pass confirms, among other things:

  • soc_new_services uses a 24h ago default window with a shard-field filter, returning full results in about 28 seconds against real data volume.

  • sre_host_headroom reports memory in GB, with an explicit unit column distinguishing it from the CPU load-average rows — matching host_memory's units.

  • The trace_* tools (v1.14.0) sort correctly: trace_find_slow casts duration to an integer before sorting, and trace_analyze orders spans by start_time. See Trace tools above.

  • claude_token_burn, claude_loop_check, and claude_model_fit (v1.14.1) parse real bzrk --json output correctly, including its Tables[0].rows/Tables[0].schema.columns shape. See Agent-log intelligence above.

Extending — add a new tool in five minutes

berserk-mcp's core idea is fixed, verified queries. Adding a tool is a short, mechanical task. Keep the routing surface small (about 20 core tools). Let less common tools accumulate behind save_query/run_saved through the learning loop.

Before writing KQL, read the Berserk KQL performance guide. It covers index-friendly predicates, tail for recency, narrow projections, explicit limits, live verification, and the shared-cluster fleet rules. As of v1.17.0, the guide's "Verified function availability" table also confirms make-series, series_fit_line, series_decompose_anomalies, series_fir, rate, deriv, bin_auto, extract_log_template, and fieldstats all work against the live cluster — every core query builder now prefers these native forms over hand-rolled bin()/sort/bag_keys equivalents where one exists.

1. Find the KQL on a live instance. Iterate with bzrk until the query returns clean rows — names, units, sort order. Do not ship a query you have not seen succeed against real data.

bzrk -P local search "default | where metric_name == 'system.network.io' \
  | summarize bytes=sum(value) by host=tostring(resource['host.name'])" \
  --since "1h ago"

2. Add the tool entry:

TOOLS.append({
    "name": "host_network",
    "roles": ["sre"],          # omit to make visible to all lanes
    "description": "Total network bytes (sum) per host. Per-HOST; for per-container "
                   "network use `search` for now.",
    "inputSchema": {"type": "object", "properties": _since()},
})
TITLES["host_network"] = "Per-Host Network I/O"

Wire it to the dispatcher (fixed cmd key), and add a KQL constant for the test.

3. Lock the query string with a test:

def test_q_host_net_locked(self):
    self.assertIn("system.network.io", bm.Q_HOST_NET)

4. Run the suite and re-register:

python -m pytest tests/ -q
claude mcp remove berserk-q && claude mcp add berserk-q -- berserk-mcp

A tool that touches free-text input (a service name) needs an allowlist — see logs_for_service. A tool that needs two bzrk round-trips can follow discover_schema's pattern. Both patterns are in the source, as templates.

Contributing

Issues, ideas, and PRs are all welcome. See CONTRIBUTING.md for the short version. The bar is low: if the tests pass, the description is narrow, and the query has been seen working against real data, it is mergeable.

Good first contributions:

  • A new fixed-query tool for telemetry you actually care about

  • A worked example for your stack (Kubernetes, ECS, Nomad, and others) under docs/

  • Sharpening a tool description that confused your model. The descriptions are the router — a clearer one is a real correctness improvement.

  • Filing an issue when you hit something berserk-mcp should have a tool for

License

MIT.

Available Tools

35 tools
bzrk_query_perfBerserk Query PerformanceA
Read-onlyIdempotent

Berserk query engine latency percentiles: p50, p95, p99 in µs. Use for 'how fast is Berserk?', 'query latency', or 'p50/p95/p99 execution time'. Uses otel_histogram_percentile($raw, N) — the native Berserk histogram aggregate.

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.

TDQS

A4.3/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true, openWorldHint=true, idempotentHint=true, destructiveHint=false. Description adds value by specifying the exact percentiles and unit (µs), and mentions the implementation function, without contradicting annotations.

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?

Two sentences, no redundancy. First sentence states purpose, second adds usage guidance and implementation detail. Perfectly concise and front-loaded.

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

Completeness5/5

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

For a simple read-only metric tool with one optional parameter, the description covers what the tool returns (percentiles, unit), when to use it, and includes implementation hint. No output schema needed. Complete for its complexity.

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

Parameters3/5

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

Schema description coverage is 100% for the single parameter 'since', with clear examples. The description does not add extra meaning beyond the schema, so baseline 3 applies.

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 explicitly states the tool returns Berserk query engine latency percentiles (p50, p95, p99) in microseconds, using a specific verb-resource combination. It distinguishes from sibling tools by focusing on a unique metric.

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

Usage Guidelines4/5

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

Provides explicit use cases ('how fast is Berserk?', 'query latency', 'p50/p95/p99 execution time'), guiding when to invoke. Does not explicitly contrast with alternatives, but clarity makes it easy to decide.

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

claude_errorsClaude Code: Tool ErrorsA
Read-onlyIdempotent

Claude Code tool errors — failed tool results (is_error=true) with a body snippet. Default 6h.

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.

TDQS

A3.9/5.0
Behavior4/5

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

Annotations already declare readOnlyHint and idempotentHint, and description adds that results are failed tool results with body snippet and default 6h window, providing useful behavioral context beyond annotations.

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?

Extremely concise: one sentence that front-loads the core purpose and includes default behavior. No wasted words.

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

Completeness5/5

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

For a simple read-only tool with one optional parameter and no output schema, the description provides sufficient information about what it returns and default behavior. Complete.

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

Parameters3/5

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

Only one parameter 'since' with schema description of time window examples. Schema coverage is 100%, so description adds no extra meaning beyond schema. Baseline score of 3 applies.

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 retrieves Claude Code tool errors (failed tool results with body snippet) and specifies a default 6-hour window. It is specific and distinct from sibling tools like claude_recent or errors_by_service.

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

Usage Guidelines2/5

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

No guidance on when to use this tool versus alternatives like errors_by_service or soc_high_severity_logs. The description only states what it does without providing context for selection.

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

claude_recentClaude Code: Recent ActivityA
Read-onlyIdempotent

Recent Claude Code activity (timestamp, type, role, model, tool names, error flag), newest first. Default window 1h.

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.

TDQS

A4.3/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and non-destructive behavior. The description adds valuable context about returned fields, newest-first ordering, and a default 1-hour window, going beyond the structured data.

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?

One concise sentence, front-loading key information: content, ordering, and default window. No wasted words.

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

Completeness5/5

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

Given the low complexity (one optional parameter, no output schema, full annotations), the description is complete. It covers all essential aspects for agent understanding and invocation.

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?

Schema description coverage is 100% for the single 'since' parameter. The description adds the default window of 1 hour, which is not present in the schema, thus providing extra guidance beyond the schema's description.

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 lists recent Claude Code activity with specific fields (timestamp, type, role, model, tool names, error flag). It distinguishes from sibling tools like claude_errors and claude_search by focusing on a broad chronological feed.

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

Usage Guidelines3/5

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

The description does not explicitly state when to use this tool versus alternatives or provide exclusions. While the context implies use for recent activity, no direct guidance is given for choosing among siblings.

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

claude_sessionsClaude Code: SessionsA
Read-onlyIdempotent

Claude Code sessions rollup: events, first/last seen, assistant turns, tool turns, and error count per session. Default 6h.

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.

TDQS

A4.2/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and destructiveHint. The description adds value by specifying that it is a rollup and indicating the default time window (6h), which goes beyond the annotation hints.

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?

Very concise, single sentence with a clear list of returned metrics and a default value. No wasted words, purpose is front-loaded.

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?

For a simple tool with one optional parameter and no output schema, the description covers the core functionality and default behavior. It could optionally clarify the response format, but the provided information is sufficient for basic usage.

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?

Schema coverage for the only parameter 'since' is 100%. The description adds a default time window ('Default 6h'), providing additional context beyond the schema description.

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?

Description clearly states the tool provides a rollup of Claude Code sessions including specific metrics (events, first/last seen, assistant turns, tool turns, error count). It distinguishes itself from sibling tools like claude_errors, claude_recent, and claude_search by focusing on session-level aggregation.

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

Usage Guidelines3/5

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

Implies usage for obtaining session summary metrics with a default time window of 6 hours, but does not explicitly state when to use this tool over siblings or any conditions for non-use.

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

claude_toolsClaude Code: Tool HistogramA
Read-onlyIdempotent

Claude Code tool-use histogram — how many times each tool (Bash, Edit, Read, ...) was used. Default 6h.

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.

TDQS

A4/5.0
Behavior3/5

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

Annotations fully cover read-only, open-world, idempotent, and non-destructive traits. The description adds only the default time window, which is a minor behavioral detail. No additional traits (e.g., return format, pagination) are disclosed, but annotations already provide strong safety signals.

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?

Description is one sentence, immediately stating the tool's purpose and a key behavioral detail (default window). No wasted words; every part contributes value.

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?

With one well-documented parameter, comprehensive annotations, and no output schema, the description is largely complete. It communicates the core function and default behavior. Could mention that it returns counts per tool, but this is implied by 'histogram.'

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?

The single parameter 'since' is fully described in the schema with examples. The tool description adds the default value of 6 hours, which provides useful context beyond the schema. With 100% schema coverage, this extra default information elevates the score.

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?

Description clearly states the tool provides a histogram of Claude Code tool usage, specifying the resource ('tool-use') and verb ('histogram'). The title and description together distinguish it from sibling tools like claude_errors or claude_recent, which focus on different aspects.

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

Usage Guidelines3/5

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

The description mentions a default time window ('Default 6h') but does not explicitly guide when to use this tool versus alternatives. Usage context is implied (when you need tool usage counts), but no exclusions or sibling comparisons are provided.

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

container_hostsContainer → Host MapA
Read-onlyIdempotent

Map each container to the host/VM it runs on. Use to answer 'which host runs container X' or to JOIN per-container metrics (top_cpu/top_memory) with per-host metrics (host_cpu/host_memory) — don't infer the host from the container's name.

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.

TDQS

A4/5.0
Behavior3/5

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

Annotations already provide strong safety signals (readOnly, not destructive), and the description adds minimal internal behavior details beyond usage guidance, such as how the mapping is resolved.

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?

The description is two concise sentences, front-loaded with purpose and followed by use cases, with no wasted words.

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?

For a simple read-only tool with one optional parameter and no output schema, the description covers main usage and joins, but could mention the output structure for completeness.

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

Parameters3/5

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

The input schema covers the single parameter 'since' with a clear description (100% coverage), and the tool description adds no additional parameter semantics beyond what the schema already provides.

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 maps containers to hosts, provides specific use cases (answering 'which host runs container X' and joining per-container with per-host metrics), and explicitly distinguishes from inferring host from container name, setting it apart from siblings.

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

Usage Guidelines4/5

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

The description gives explicit when-to-use scenarios and a caution against inferring host from name, but does not explicitly list alternatives or exclusion criteria beyond the sibling context implied by the join hint.

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

discover_schemaDiscover SchemaA
Read-onlyIdempotent

Discover the shape of a data source: returns (1) every key present under resource with row counts, AND (2) a small sample of real rows so you can read the actual values. Use to learn an unknown or newly-ingested source before querying it. Optional service filter. Pair with list_services / list_metrics. Once you work out a query with search, persist it with save_query so it becomes reusable.

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.
serviceNooptional: limit to one service.name

TDQS

A4.3/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, idempotentHint, and openWorldHint. The description adds context about returning sample rows (not full data) and an optional filter, which adds behavioral insight beyond the annotations. It does not contradict annotations, and is consistent.

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?

The description is concise, front-loaded with the main purpose and outputs, and provides usage guidance without unnecessary words. Every sentence adds value.

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

Completeness5/5

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

Despite no output schema, the description explains exactly what is returned (keys with row counts, sample rows). It also covers the workflow and usage context. For a simple tool with only 2 optional params, this is complete.

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

Parameters3/5

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

Schema coverage is 100%, so baseline is 3. The description mentions 'Optional service filter' but doesn't add extra meaning beyond the schema description for 'since' (time window). Thus it adds marginal value.

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 verb 'Discover' and the resource 'shape of a data source', lists specific outputs (keys with row counts, sample rows), and distinguishes itself from siblings by pairing with list_services/list_metrics and outlining a workflow with search and save_query.

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

Usage Guidelines4/5

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

It explicitly says 'Use to learn an unknown or newly-ingested source before querying it', pairs with list_services/list_metrics, and provides a sequence (search, then save_query). While it lacks explicit 'when not to use' or full alternatives, the guidance is strong and clear.

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

discovery_statusDiscovery StatusA
Read-onlyIdempotent

List pending and completed discovery jobs for new services or metrics.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A3.9/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint. The description adds no further behavioral details (e.g., pagination, ordering, rate limits). It aligns with annotations but provides minimal extra transparency.

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?

A single, well-structured sentence that is front-loaded and contains no extraneous information.

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

Completeness3/5

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

Given no output schema and simple operation, the description is adequate for basic understanding but does not clarify return format or behavior. It could be more complete but covers the essentials.

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?

No parameters exist, and schema coverage is 100%. According to the rubric, 0 parameters baseline is 4. The description adds no parameter info, but none is needed.

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 lists pending and completed discovery jobs, using a specific verb and resource. It distinguishes from sibling tools like request_discovery (which creates jobs) and discover_schema.

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

Usage Guidelines3/5

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

The description implies when to use (to list jobs) but does not explicitly state when not to use or mention alternatives. The context suggests it is for reading, but no exclusion criteria are provided.

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

errors_by_serviceErrors by ServiceA
Read-onlyIdempotent

Count of ERROR-level log lines grouped by service. Use for 'how many errors', 'which services have errors', or 'any errors?' — gives counts, not log text. For the actual error messages, use logs_for_service with the service name from this result.

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.

TDQS

A4.3/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true, destructiveHint=false, idempotentHint=true. Description adds that it gives counts not log text, which is consistent but does not significantly supplement beyond annotations.

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?

Two concise sentences with zero waste. First sentence states purpose and use cases, second sentence provides guidance on alternative tool. Front-loaded with essential information.

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

Completeness5/5

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

For a simple tool with one parameter and no output schema, the description explains exactly what the output is (counts grouped by service), when to use it, and how to proceed to get log text. No gaps remain.

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

Parameters3/5

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

Schema coverage is 100%, and the schema already describes the 'since' parameter well with an example. Description does not add additional meaning or format details beyond the schema, so baseline score of 3 is appropriate.

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?

Description clearly states the tool counts ERROR-level log lines grouped by service, with specific verb 'Count' and resource 'ERROR-level log lines grouped by service'. It distinguishes from logs_for_service by noting it gives counts not log text. Use cases are listed explicitly.

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?

Description provides explicit when to use ('how many errors', 'which services have errors', 'any errors?') and when not to use (for actual error messages, use logs_for_service). This directly contrasts with a sibling tool, giving clear guidance.

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

host_cpuPer-Host CPU LoadA
Read-onlyIdempotent

Average CPU load (1-minute load average) per host. Use for per-host CPU AND as the DEFAULT for ambiguous whole-machine questions — 'the box', 'the system', 'the server', 'the machine', 'what's hammering/running hot' are about the hosts, not containers (top_cpu is per-CONTAINER).

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false. The description adds specific behavioral context: it returns '1-minute load average' and is per-host. No contradictions. Adds value beyond annotations.

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?

Two sentences front-loaded with key information. No wasted words. Every sentence earns its place.

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

Completeness5/5

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

Given the tool's simplicity (one optional parameter, no output schema), the description covers the metric, use case, and sibling differentiation. No missing critical information.

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

Parameters3/5

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

Schema has 100% coverage for the single parameter 'since', so baseline is 3. The description does not add additional meaning to the parameter beyond what the schema provides. No extra info.

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 it provides 'Average CPU load (1-minute load average) per host' and distinguishes itself from the sibling tool top_cpu by specifying that top_cpu is per-container. This meets the criteria of specific verb+resource and differentiates from siblings.

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 states when to use: 'Use for per-host CPU AND as the DEFAULT for ambiguous whole-machine questions... are about the hosts, not containers (top_cpu is per-CONTAINER).' This provides clear when-to-use and when-not-to-use guidance.

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

host_memoryPer-Host MemoryA
Read-onlyIdempotent

Used memory in GB per host. Use for per-host memory AND as the DEFAULT for ambiguous whole-machine memory questions ('the box', 'the system', 'the server') — these are about the hosts, not containers (top_memory is per-CONTAINER).

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.

TDQS

A4.5/5.0
Behavior4/5

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

Annotations cover safety (readOnly, idempotent, not destructive). Description adds context about return unit (GB) and handles ambiguous queries. No contradictions.

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?

Two sentences, no wasted words. Front-loaded with purpose, then usage directive. Highly efficient.

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

Completeness5/5

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

For a simple 1-param read-only tool without output schema, the description fully covers what, when, and how to use, including disambiguation.

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

Parameters3/5

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

Schema has 100% coverage for the single parameter 'since'. Description does not add extra information beyond the schema's description.

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?

Clearly states 'Used memory in GB per host.' and distinguishes from sibling tool top_memory (per-container). Specific verb+resource+scope.

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: 'Use for per-host memory AND as the DEFAULT for ambiguous whole-machine memory questions.' Also states alternative for containers: top_memory.

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

list_containersList ContainersA
Read-onlyIdempotent

List all containers currently sending metrics to Berserk (with sample counts).

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.

TDQS

A4/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and no destructiveness. The description adds value by specifying that the list is limited to containers actively sending metrics and that sample counts are included, providing useful behavioral context beyond the annotations.

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?

The description is a single, 12-word sentence that conveys the essential purpose and scope without any extraneous words. It is perfectly front-loaded.

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?

For a simple tool with one optional parameter, rich annotations, and many sibling tools, the description provides clear scope and a hint of output (sample counts). It does not explain return format or pagination, but for such a tool, this is acceptable; the description is nearly complete.

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

Parameters3/5

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

The input schema has 100% description coverage for the single parameter 'since', with clear examples. The description does not add any additional information about the parameter, so the baseline score of 3 is appropriate.

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 verb 'list', the resource 'containers', and the specific scope 'currently sending metrics to Berserk with sample counts'. This effectively distinguishes it from sibling tools like list_hosts and list_services.

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

Usage Guidelines3/5

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

The description implies usage for listing active containers, but does not provide explicit guidance on when to use this tool versus alternatives, nor any exclusions or prerequisites. Given the tool's simplicity, the implied context is adequate but not strong.

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

list_hostsList HostsA
Read-onlyIdempotent

All hosts reporting telemetry, by record count.

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.

TDQS

A4.1/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and destructiveHint. The description adds that results are ordered by record count, which is a behavioral detail beyond annotations. No contradictions.

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

Conciseness4/5

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

The description is a single sentence, appropriately concise for a simple tool. It is front-loaded with the purpose. No unnecessary content, though slightly more detail could be tolerated.

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

Completeness3/5

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

No output schema exists, so the description should hint at return structure. It states ordering by record count but does not specify fields (e.g., hostname, count). Given the simplicity and annotations, it is minimally adequate but could be more complete.

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

Parameters5/5

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

Schema coverage is 100% for the single parameter 'since'. The description provides concrete examples ('15m ago', '1h ago', '2d ago') that clarify the expected format, adding significant meaning beyond the schema's type definition.

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 verb 'list' and the resource 'hosts', and specifies the ordering 'by record count'. It distinguishes from sibling tools like container_hosts, host_cpu, and host_memory which target different scopes or metrics.

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

Usage Guidelines3/5

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

No explicit when-to-use or when-not-to-use guidance is provided. The phrase 'All hosts reporting telemetry' implies a broad scope, but alternatives such as search tools or filtering methods are not mentioned.

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

list_metricsList MetricsA
Read-onlyIdempotent

List every metric name currently being ingested, with sample counts + last-seen. Use to DISCOVER what telemetry exists before writing a search query.

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.

TDQS

A4.3/5.0
Behavior4/5

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

Annotations already convey read-only, idempotent, and non-destructive behavior. The description adds the context of returning sample counts and last-seen, and the discovery purpose. No contradictions; the description complements annotations well.

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?

Two concise sentences: first states what the tool does and outputs, second provides usage guidance. No wasted words, front-loaded with key information.

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

Completeness5/5

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

For a simple tool with one optional parameter and no output schema, the description is complete. It explains the return value (metric names, sample counts, last-seen) and the use case (discovery before search).

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

Parameters3/5

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

Schema coverage is 100% with one optional parameter 'since' described. The description does not add any parameter-specific meaning beyond the schema, so baseline 3 is appropriate.

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 specifies the verb 'list', the resource 'metric names', and provides additional details about the output ('sample counts + last-seen'). It clearly distinguishes from sibling tools by focusing on discovery before writing a search query.

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

Usage Guidelines4/5

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

The description explicitly says 'Use to DISCOVER what telemetry exists before writing a `search` query', providing clear context for when to use. It does not explicitly list exclusions or compare to all siblings, but the guidance is direct and helpful.

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

list_savedList Saved QueriesA
Read-onlyIdempotent

List previously-saved custom queries (name + description). For a non-standard question, CHECK HERE FIRST before writing new KQL.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.3/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false. The description adds the behavioral detail that the output includes 'name + description', which is useful but not critical. No contradictions.

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?

Two short sentences front-load the purpose and usage guidance. Every word serves a purpose; no repetition or fluff.

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

Completeness5/5

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

For a simple list tool with no parameters and no output schema, the description fully covers what the tool does and when to use it. Annotations handle safety. The mention of output fields compensates for lack of output schema.

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?

The input schema has zero parameters, so coverage is trivially 100%. The description does not need to add parameter details. The baseline for 0 params is 4, which is appropriate.

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 'List previously-saved custom queries (name + description).' It uses a specific verb ('list') and defines the resource ('previously-saved custom queries') along with the output fields. This distinguishes it from siblings like run_saved and save_query.

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

Usage Guidelines4/5

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

The description provides explicit guidance: 'For a non-standard question, CHECK HERE FIRST before writing new KQL.' This tells the agent when to use this tool (before writing new queries) and implies an alternative (writing new KQL). It does not explicitly list all when-not-to-use scenarios, but the context is clear.

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

list_servicesList ServicesA
Read-onlyIdempotent

All services/sources sending data, with log vs metric breakdown. Best default for 'what's running?', 'what's reporting?', or 'what services are there?' — shows everything. For just hosts use list_hosts; for just containers use list_containers.

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already declare it as read-only, idempotent, and non-destructive. The description adds that it returns all services with a breakdown, which is helpful. Could mention if results are ordered or limited.

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?

Two sentences that are front-loaded: first defines the tool, second provides usage guidance. No redundant information; every sentence adds value.

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?

For a simple list tool with one parameter and no output schema, the description conveys the main result structure (log vs metric breakdown). Could be slightly more explicit about ordering or limits, but adequate.

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

Parameters3/5

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

Schema coverage is 100% with a clear description for the single optional parameter 'since'. The tool description does not add extra meaning beyond the schema, so a baseline score of 3 is appropriate.

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 lists all services/sources with a log vs metric breakdown, and provides example queries it answers. It explicitly distinguishes from siblings list_hosts and list_containers.

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?

Describes when to use ('what's running?', 'what's reporting?') and when not to ('For just hosts use list_hosts; for just containers use list_containers'). Provides explicit alternatives.

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

logs_for_serviceService LogsA
Read-onlyIdempotent

Recent log lines for a specific service e.g. 'nginx', 'postgres'. Use for 'show me the errors/logs from X' — returns actual log text. For error COUNTS across all services, use errors_by_service first, then drill into a specific service here.

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.
serviceYesservice.name value

TDQS

A3.9/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, which covers most behavioral expectations. The description adds that it 'returns actual log text' and implies the tool is safe for repeated use (non-destructive). However, it does not elaborate on any edge cases or limitations beyond what annotations provide.

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?

The description is extremely concise—two sentences that each serve a distinct purpose. The first sentence states the primary function with examples; the second provides usage guidance with an alternative. No superfluous language.

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

Completeness3/5

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

The tool has no output schema, so the description should compensate by explaining the format of the returned log lines. It only says 'returns actual log text', which is vague. It could mention common fields like timestamp, level, message. Additionally, there is no mention of result limits or pagination, which are common for log retrieval. However, given the large number of sibling tools, the description adequately focuses on the key differentiator.

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

Parameters3/5

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

The input schema has 100% coverage, providing full descriptions for both parameters. The description adds example values for service ('nginx', 'postgres') which reinforces meaning but does not introduce new semantics. The since parameter format is already detailed in the schema, so no additional value is added.

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 verb (get/recent log lines), resource (specific service), and provides concrete examples ('nginx', 'postgres'). It effectively distinguishes from sibling tools like errors_by_service, which handles counts across all services.

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

Usage Guidelines4/5

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

The description explicitly advises to use errors_by_service first for error counts, then drill into a specific service with this tool. It provides use case examples ('show me the errors/logs from X'). The guidance is clear but could be more exhaustive about alternatives.

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

request_discoveryRequest DiscoveryA
Idempotent

Queue a newly-added service or metric for author-lane integration. Validates the source is currently visible in Berserk, then records a job for the discovery worker to drain. Use when a user says 'I added / connected / started shipping SOURCE'.

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.
metricNometric name to integrate
serviceNoservice.name to integrate
role_hintNooptional target role: sre, soc, claude, ops
requested_byNooptional requester label

TDQS

A4.2/5.0
Behavior4/5

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

Annotations already indicate idempotentHint=true, destructiveHint=false, and readOnlyHint=false. The description adds behavioral context: 'Validates the source is currently visible in Berserk, then records a job for the discovery worker to drain.' This informs the agent about internal validation and queuing, which is beyond what annotations provide. Missing details about error handling or what happens on validation failure.

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?

The description is very concise: two sentences plus a one-line usage hint. It front-loads the primary purpose and includes key details without excess. Every sentence adds value.

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?

Given the tool's simplicity, no output schema, and thorough annotations, the description covers the essential aspects: purpose, usage trigger, and internal steps. It could be improved by mentioning the job destination or potential confirmation, but is still fairly complete.

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

Parameters3/5

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

Schema description coverage is 100%, so baseline is 3. The description does not add significant extra meaning to parameters; it mentions 'source' but does not map directly to parameters. The schema already describes each parameter adequately.

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 action: 'Queue a newly-added service or metric for author-lane integration.' It explains the validation and job recording steps, and provides a specific use case ('when a user says I added / connected / started shipping SOURCE'). This effectively distinguishes it from sibling tools like discovery_status or discover_schema.

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

Usage Guidelines4/5

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

The description explicitly advises when to use the tool: 'Use when a user says I added / connected / started shipping SOURCE.' This provides clear context. However, it does not include when not to use or mention alternative tools, though the sibling list implicitly offers alternatives.

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

run_savedRun Saved QueryA
Read-onlyIdempotent

Run a previously-saved query by name (see list_saved). Deterministic - no KQL authoring.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYessaved query name
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.

TDQS

A4/5.0
Behavior3/5

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

Annotations already provide readOnlyHint, idempotentHint, etc. The description adds 'Deterministic' and 'no KQL authoring', which align with annotations but do not disclose additional behavioral traits like response format or potential side effects. Since annotations carry most of the burden, the description adds minimal value beyond what is structured.

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?

Two sentences, no wasted words. First sentence states the primary action and resource, second adds two key behavioral traits (deterministic, no KQL authoring). Front-loaded and perfectly concise.

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?

For a simple read-only tool with good annotations and two well-described parameters, the description covers the essential: what it does, how to get the query name, and key behavioral trait. However, it does not mention the output format or that results are returned, which could be assumed but is not explicitly stated. Overall sufficient but could be slightly more complete.

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

Parameters3/5

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

Schema description coverage is 100% with clear descriptions for name and since parameters. The description adds only marginal value: 'by name' is already implied, and 'see list_saved' helps with name provenance but does not reveal new semantic details. Baseline 3 is appropriate as schema does the heavy lifting.

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 runs a previously-saved query by name, referencing list_saved for finding names. It distinguishes from sibling tools like save_query and search by specifying 'Deterministic - no KQL authoring', making the purpose unambiguous.

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

Usage Guidelines4/5

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

The description implies when to use: when you have a saved query name and want deterministic results without writing KQL. It references list_saved for obtaining names, but does not explicitly state when not to use or compare to alternatives like search or save_query. The guidance is clear but lacks exclusions.

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

save_querySave QueryA
Idempotent

Persist a WORKING KQL query as a reusable named query so it never has to be figured out again. Call this after you answer a non-standard question with a custom search query. The query is run once to verify it works; if it errors it is NOT saved.

ParametersJSON Schema
NameRequiredDescriptionDefault
kqlYesKQL starting with 'default | ...'
nameYesshort snake_case name
rolesNooptional role(s) this query serves: sre, soc, claude, ops
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.
descriptionYeswhat the query answers

TDQS

A4.1/5.0
Behavior4/5

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

Discloses beyond annotations: the query is run once to verify, and if it errors it is NOT saved. Annotations already indicate non-read-only and non-destructive, but description adds verification behavior.

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

Conciseness4/5

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

Two sentences, front-loaded with main purpose. Efficient but could be more structured (e.g., bullet points).

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?

With full schema and annotations, description adds enough context for typical use. Could mention success outcome (e.g., query becomes available in list_saved/run_saved).

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

Parameters3/5

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

Schema coverage is 100%, so description does not need to add parameter details. It does not provide additional semantics beyond the schema.

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?

Clearly states the verb 'persist' and resource 'KQL query as a reusable named query'. Distinguishes from siblings like 'run_saved' and 'list_saved' by emphasizing saving after answering a non-standard question.

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

Usage Guidelines4/5

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

Explicitly instructs 'Call this after you answer a non-standard question with a custom search query'. Adds condition that query is verified before saving, providing clear context.

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

schemaSchema IntrospectionA
Read-onlyIdempotent

Show Berserk tables + column schema (live introspection).

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A3.5/5.0
Behavior3/5

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

Annotations already declare readOnly, openWorld, idempotent, and non-destructive hints. The description adds 'live introspection', confirming real-time behavior. No contradictions, but little additional value beyond annotations.

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?

Single sentence that is front-loaded and concise, containing all necessary information without extraneous text.

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?

For a zero-parameter tool with rich annotations, the description adequately conveys the purpose. However, it does not mention the structure or format of the returned schema, which could be useful.

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?

No parameters exist, so the description does not need to provide parameter semantics. Baseline score of 4 applies as there is nothing to document.

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

Purpose4/5

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

The description clearly states the tool shows Berserk tables and column schema via live introspection. However, it does not differentiate from the sibling 'discover_schema', which may have overlapping functionality.

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

Usage Guidelines2/5

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

No guidance is provided on when to use this tool versus alternatives like 'discover_schema'. The description is purely definitional without usage context.

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

soc_high_severity_logsSOC: High Severity LogsA
Read-onlyIdempotent

SOC view of recent CRITICAL/FATAL/ERROR logs with service and message text. Use for 'show critical events', 'recent incident logs', or 'what looks severe right now'.

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.

TDQS

A4.1/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true, destructiveHint=false, and idempotentHint=true, so the safety profile is clear. The description adds that logs are 'recent' and include service and message text, which provides some behavioral context but does not significantly extend beyond what annotations imply. No contradictions.

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?

The description is a single sentence stating the purpose, followed by three example queries. Every part is relevant and there is no redundancy. It is front-loaded with the core function.

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

Completeness5/5

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

For a simple tool with one parameter and no output schema, the description completely covers what the tool does and when to use it. It implies the return format (logs with service and message text) and the scope (recent, high severity). No additional information is needed for effective use.

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

Parameters3/5

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

The schema coverage is 100% with one optional parameter 'since' fully described in the schema with a clear example. The description does not mention the parameter at all, so it adds no additional meaning beyond the schema. Baseline score for high coverage is 3.

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 provides CRITICAL/FATAL/ERROR logs with service and message text. It distinguishes itself from sibling tools like soc_log_spike and soc_repeated_errors by focusing on severity rather than spikes or repetitions. Example queries ('show critical events', 'recent incident logs') further clarify the purpose.

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

Usage Guidelines4/5

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

The description provides explicit query examples ('show critical events', 'recent incident logs', 'what looks severe right now') that indicate common use cases. It does not explicitly state when not to use the tool or offer alternatives, but the context is clear and the examples cover the typical usage.

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

soc_log_spikeSOC: Log SpikeA
Read-onlyIdempotent

SOC view of services with the largest log volume per minute. Use for 'anything anomalous', 'which source is spiking', or 'suspicious burst of logs'.

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.

TDQS

A4/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and destructiveHint false. The description adds 'SOC view' and 'largest log volume per minute', which is consistent but does not disclose additional behavioral traits beyond what annotations provide. No contradiction.

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?

Two crisp sentences: the first states the core function, the second provides usage examples. Every sentence earns its place with no wasted words.

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?

For a simple read-only list tool with one optional parameter, the description covers purpose and usage adequately. Not mentioning output format is acceptable since no output schema exists and the tool's result is intuitive (list of services with log volume).

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

Parameters3/5

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

Schema coverage is 100% with a single parameter 'since' that has a clear description. The tool description does not add any extra meaning or guidance about the parameter; baseline 3 is appropriate.

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 specifies 'SOC view of services with the largest log volume per minute', clearly stating the verb (view), resource (services), and scope (log volume). It also includes example use cases in quotes, distinguishing it from sibling tools like 'soc_high_severity_logs' or 'soc_timeline'.

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

Usage Guidelines4/5

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

Explicit use cases are provided: 'anything anomalous', 'which source is spiking', 'suspicious burst of logs'. While no alternatives are explicitly mentioned, the examples give clear context for when to invoke this tool.

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

soc_new_servicesSOC: New ServicesA
Read-onlyIdempotent

SOC view of services ordered by first-seen time. Use for 'what is new', 'anything first-seen', or 'did a new source appear'.

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.

TDQS

A4.3/5.0
Behavior3/5

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

Annotations already provide readOnly, openWorld, idempotent, non-destructive hints. The description adds the behavioral detail of 'ordered by first-seen time'. However, no mention of output fields or pagination, which would be helpful given no output schema.

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?

Two sentences, front-loaded with purpose, no fluff. Every word adds value.

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?

For a simple read-only tool with one optional parameter, the description is adequate. It could mention the output format, but given annotations cover safety and the use cases are clear, it is mostly complete.

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

Parameters5/5

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

The input schema covers 100% of parameters with descriptions. The description adds value by explaining the context of 'first-seen time' and the parameter 'since' has examples in its description.

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 returns a SOC view of services ordered by first-seen time, and provides specific use cases ('what is new', 'anything first-seen', 'did a new source appear'). This distinguishes it from sibling tools like list_services which likely list all services without such ordering.

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

Usage Guidelines4/5

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

The description explicitly tells when to use the tool: for queries about new or first-seen services. It does not explicitly name alternatives, but the use-case phrases guide appropriate usage clearly.

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

soc_repeated_errorsSOC: Repeated ErrorsA
Read-onlyIdempotent

SOC view of error messages that appear more than 5 times — potential probes, loops, or persistent incidents. Use for 'what keeps repeating' or 'show recurring failures'.

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.

TDQS

A4.2/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, openWorldHint, etc. The description adds the threshold of 'more than 5 times' and potential interpretations (probes, loops, incidents), which is valuable beyond annotations.

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?

Two sentences with zero wasted words. Front-loaded with the condition and purpose, followed by usage examples.

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?

For a simple list tool with rich annotations and one parameter, the description covers threshold, purpose, and example queries. No output schema exists, but the context is sufficient for an agent to use the tool correctly.

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

Parameters3/5

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

Schema description coverage is 100% for the single parameter 'since'. The description does not add extra meaning beyond the schema's, achieving baseline adequacy.

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 it provides a SOC view of error messages appearing more than 5 times, distinguishing it as a tool for recurring errors rather than general error listing. Example queries like 'what keeps repeating' add specificity.

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

Usage Guidelines4/5

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

Explicitly suggests use cases with example phrases ('what keeps repeating', 'show recurring failures'), providing clear guidance. Lacks explicit exclusion of alternatives but the context is strong enough.

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

soc_timelineSOC: Incident TimelineA
Read-onlyIdempotent

SOC incident timeline for one service: timestamps, severity, metric names, and message snippets. Use for 'timeline for service X' or 'reconstruct incident for X'.

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.
serviceYesservice.name value

TDQS

A3.6/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint, openWorldHint, and destructiveHint false. Description adds what data is returned (timestamps, severity, metric names, message snippets), which is useful but does not reveal any behavioral quirks beyond annotations. No contradictions.

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?

Two concise sentences: first describes output content, second gives example use cases. No wasted words, front-loaded with key information. Ideal length for this tool.

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?

Despite no output schema, description lists expected fields (timestamps, severity, metric names, message snippets), which is sufficient for an agent. Could mention ordering or limits, but for a simple read-only timeline, it is largely complete.

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

Parameters3/5

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

Input schema has 100% coverage; both 'since' and 'service' are described. Description does not add extra meaning or examples beyond schema. Baseline 3 is appropriate.

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

Purpose4/5

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

Description clearly states it returns an incident timeline for one service, listing timestamps, severity, metric names, and message snippets. It gives specific use cases ('timeline for service X', 'reconstruct incident for X'). While it doesn't explicitly differentiate from all sibling tools like soc_high_severity_logs, the purpose is clear and distinct.

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

Usage Guidelines3/5

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

Provides usage cases ('Use for timeline for service X or reconstruct incident for X'), but lacks guidance on when not to use or comparisons to alternatives among many sibling SOC tools. Some implicit context but not exhaustive.

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

sre_error_rateSRE: Error RateA
Read-onlyIdempotent

SRE view of ERROR log events grouped by service and minute. Use for 'is the error rate climbing', 'which service is burning error budget', or 'what should we rollback first'.

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.

TDQS

A4.1/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true and destructiveHint=false. The description adds behavioral context: it groups by service and minute, and focuses on ERROR logs. This goes beyond annotations without contradiction.

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?

The description is extremely concise: two sentences cover the tool's purpose and key usage patterns with no wasted words. It is front-loaded with the core definition.

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

Completeness3/5

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

For a simple single-parameter tool, the description explains the grouping and usage scenarios adequately. However, without an output schema, it could be more complete by describing the return format (e.g., list of services with error counts, time series).

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

Parameters3/5

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

Schema coverage is 100% and the parameter description gives example values ('15m ago', '1h ago'). The tool description does not add extra semantics beyond the schema, so baseline score of 3 is appropriate.

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 it provides an SRE view of ERROR log events grouped by service and minute, and gives specific use cases like 'is the error rate climbing' and 'which service is burning error budget'. This differentiates it from sibling tools by specifying grouping and temporal focus.

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

Usage Guidelines4/5

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

The description provides explicit when-to-use scenarios (error rate climbing, budgeting, rollback decisions). However, it does not exclude alternatives or explain when not to use this tool compared to similar siblings like claude_errors or errors_by_service.

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

sre_host_headroomSRE: Host HeadroomA
Read-onlyIdempotent

SRE view of host CPU load and memory used side-by-side. Use for 'which host is hottest', 'where is headroom lowest', or 'which VM is nearest saturation'.

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.

TDQS

A4.1/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true, destructiveHint=false, and idempotentHint=true, so the description does not need to reiterate safety. The description adds that the tool shows CPU and memory side-by-side, which is useful but does not disclose additional behavioral traits beyond what annotations provide.

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?

The description is highly concise: two sentences. The first sentence defines the tool's function, and the second provides usage examples. No wasted words; each sentence earns its place.

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

Completeness5/5

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

The tool is simple with one optional parameter and no output schema. The description fully explains its purpose and usage scenarios. Given the low complexity, it is complete and sufficient for an agent to know when and how to use it.

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

Parameters3/5

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

There is only one parameter 'since' with a description in the schema. The schema coverage is 100%, and the description does not add any extra meaning or usage details beyond the schema. Baseline of 3 is appropriate.

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's purpose: an SRE view of host CPU load and memory side-by-side. It provides specific use cases ('which host is hottest', 'where is headroom lowest', 'which VM is nearest saturation'), effectively distinguishing it from sibling tools like host_cpu, host_memory, top_cpu, and top_memory.

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

Usage Guidelines4/5

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

The description explicitly says 'Use for' followed by three example queries, providing clear context on when to use the tool. It does not explicitly state when not to use or mention alternatives, but the examples give sufficient guidance for typical scenarios.

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

sre_ingest_healthSRE: Ingest HealthA
Read-onlyIdempotent

SRE view of Berserk ingest lag and dropped-data signals per host. Use for 'is ingest healthy', 'are we dropping telemetry', or 'is observability lagging'.

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.

TDQS

A4.3/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false. The description adds context about what signals are shown (lag, dropped-data per host), which goes beyond annotations. No contradictions.

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?

Two sentences with no wasted words. The purpose is front-loaded, followed by usage examples. Every sentence earns its place.

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

Completeness5/5

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

Given single parameter, full schema coverage, and thorough annotations, the description is complete enough for a health monitoring tool. No output schema needed for this use case.

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

Parameters3/5

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

Schema coverage is 100% with one parameter 'since' described. The description does not add further parameter details beyond the schema, so baseline 3 is appropriate.

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 uses a specific verb+resource: 'SRE view of Berserk ingest lag and dropped-data signals per host.' It includes example queries like 'is ingest healthy', clearly distinguishing it from sibling tools like sre_error_rate or sre_service_health.

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

Usage Guidelines4/5

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

Explicitly states when to use with common questions: 'Use for 'is ingest healthy', 'are we dropping telemetry', or 'is observability lagging'.' Lacks when-not-to-use or alternative tools, but context is clear given sibling tool names.

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

sre_service_healthSRE: Service HealthA
Read-onlyIdempotent

SRE health rollup for one service: total events, error count, logs, metrics, last seen. Use for 'is service X healthy' or 'rollback signal for X'.

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.
serviceYesservice.name value

TDQS

A4.2/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and non-destructive. The description adds value by specifying the exact output composition (events, errors, logs, metrics, last seen), which goes beyond the annotations. No contradictions.

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?

The description is extremely concise (two sentences) and front-loaded with the core purpose. Every sentence earns its place without redundancy or fluff.

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?

Given no output schema, the description sufficiently explains what the tool returns (total events, error count, logs, metrics, last seen). It provides enough context for a simple health rollup, though it omits details like limits or ordering.

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

Parameters3/5

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

Schema coverage is 100% with both parameters described. The description does not add significant detail beyond the schema; it only restates 'service' and 'since' implicitly. Thus, baseline 3 is appropriate.

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's purpose: 'SRE health rollup for one service' listing specific data points (total events, error count, logs, metrics, last seen). It also differentiates from siblings by being a comprehensive rollup, not a focused metric like sre_error_rate or sre_host_headroom.

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

Usage Guidelines4/5

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

The description explicitly suggests use cases: 'Use for "is service X healthy" or "rollback signal for X".' This provides clear guidance on when to invoke the tool, though it does not explicitly mention when not to use it or alternatives.

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

sre_top_error_messagesSRE: Top Error MessagesA
Read-onlyIdempotent

SRE summary of the most repeated error messages by service. Use for 'what error is dominating', 'top error signatures', or 'which message to investigate first'.

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.

TDQS

A4/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and destructiveHint, so the safety profile is clear. The description adds that it is a 'summary' and groups by service, which provides some behavioral context beyond annotations. However, it does not describe result format, limit, or ordering, leaving some uncertainty.

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?

The description is concise: one sentence stating the purpose, followed by three example query forms. No redundant information, and the key action is front-loaded.

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?

For a simple tool with one optional parameter and no output schema, the description is adequate—it explains the output ('top repeated errors by service') and typical use cases. It could optionally mention result ordering or limits, but this is not essential given low complexity.

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

Parameters3/5

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

The single parameter 'since' has 100% schema description coverage, so the schema already explains its meaning. The description adds no additional semantic value beyond the schema's description, meeting the baseline expectation.

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 it provides an 'SRE summary of the most repeated error messages by service', with explicit usage examples like 'what error is dominating' and 'top error signatures'. This distinguishes it from sibling tools like 'errors_by_service' which may list all errors without focusing on frequency.

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

Usage Guidelines4/5

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

The description gives clear use cases ('Use for...') with three example queries, helping an agent decide when to invoke this tool. However, it does not explicitly mention when not to use it or compare to siblings like 'errors_by_service' or 'soc_repeated_errors'.

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

top_cpuTop Containers by CPUA
Read-onlyIdempotent

Containers ranked by CPU percent, highest first. PER-CONTAINER — use ONLY when the user names a container, says 'docker'/'container', or asks for 'top containers'. For ambiguous whole-machine questions ('the box', 'the system', 'the server', 'the machine', 'what’s hammering/running hot') use host_cpu instead.

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, idempotentHint, destructiveHint false, so safety is covered. Description adds behavioral context about ranking order and per-container scope, which enhances understanding beyond annotations.

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?

Two sentences that efficiently convey purpose and usage guidelines with explicit alternative. No wasted words.

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

Completeness5/5

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

With one optional parameter, no output schema, and comprehensive annotations, the description covers everything needed. It also provides clear sibling differentiation, making it fully complete for the tool's complexity.

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

Parameters3/5

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

Only one parameter 'since' with 100% schema coverage, including an example. Description adds no additional meaning beyond the schema, so baseline score of 3 is appropriate.

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 lists containers ranked by CPU percent, highest first, which is a specific verb+resource. It distinguishes from sibling host_cpu by specifying it's per-container vs whole-machine.

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 states when to use (user names container, says docker/container, top containers) and when not (ambiguous whole-machine questions) with explicit alternative name host_cpu.

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

top_memoryTop Containers by MemoryA
Read-onlyIdempotent

Containers ranked by memory usage in MB, highest first. PER-CONTAINER — use ONLY when the user names a container or says 'docker'/'container'. For ambiguous whole-machine memory questions ('the box', 'the system', 'the server') use host_memory instead.

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoTime window e.g. '15m ago', '1h ago', '2d ago'.

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, idempotentHint, and non-destructive, so safety is clear. The description adds that results are in MB and sorted highest first, providing useful behavioral context beyond annotations.

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?

Two sentences, front-loaded with purpose, no wasted words. The usage guidance is integrated efficiently.

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

Completeness5/5

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

For a simple, single-parameter tool with rich annotations and explicit sibling differentiation, the description covers all necessary context. No output schema is needed given the straightforward nature.

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

Parameters3/5

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

Schema coverage is 100% with a clear description for the 'since' parameter. The description does not add additional parameter semantics beyond what the schema provides, so baseline 3 is appropriate.

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 ranks containers by memory usage in MB, highest first. It explicitly distinguishes from sibling tools like host_memory by specifying 'PER-CONTAINER' and when to use it.

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?

Provides explicit conditions for use: only when user names a container or says 'docker'/'container'. For ambiguous whole-machine questions, it directs to use host_memory instead.

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

TDQS

A3.9/5.0
Disambiguation5/5

Each tool has a clearly distinct purpose, with no overlapping functionality. Multiple tools exist for logs/errors but they are separated by role (SOC vs SRE) and granularity (counts vs text, aggregated vs per-service). The descriptions explicitly clarify when to use each tool (e.g., top_cpu vs host_cpu).

Naming Consistency4/5

Most tools follow a predictable prefix_pattern (soc_, sre_, claude_, host_, list_, etc.) and use lowercase snake_case. A few deviations exist, such as 'bzrk_query_perf' using an abbreviation instead of a full word, and 'container_hosts' not following the verb-first pattern of other tools like 'list_containers'. Overall, the naming is clear and consistent enough.

Tool Count3/5

35 tools is a large number, bordering on excessive for an MCP server. While each tool has a defined role, the server covers multiple domains (Claude Code, Berserk query, containers, hosts, SOC, SRE) which may overlap in functionality. Some tools could be merged or omitted without loss of functionality, making the surface feel heavy.

Completeness4/5

The tool surface covers the core observability workflows: log analysis, metric exploration, service health, container/host monitoring, and query management. Minor gaps exist, such as no way to delete saved queries and no direct metric trend/chart tool. Overall, the set is well-rounded for the stated purpose.

Maintenance

ActivityActive
ResponsivenessResponsive

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    D
    maintenance
    Enables natural language exploration of Azure environments by generating and executing KQL queries against Azure Resource Graph. Supports multi-tenant configurations, subscription scoping, and provides direct access to Azure resource information through conversational interactions.
    8
    2
    Apache 2.0
  • A
    license
    A
    quality
    D
    maintenance
    Enables LLMs to query telemetry data via the Spyglass AI agent, providing intelligent insights about application performance, errors, and bottlenecks.
    1
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables natural language querying and analysis of OpenTelemetry traces, metrics, and logs stored in Elasticsearch/OpenSearch, allowing AI assistants to investigate performance issues, find root causes, and explore system behavior.
    16
    14
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI assistants to query and analyze data in Azure Data Explorer, Log Analytics, and Microsoft Sentinel using Kusto Query Language (KQL) through tools, resources, and prompts.
    5
    MIT

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/ssimonsen0202/berserk_mcp'

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