berserk-mcp
The berserk-mcp server provides an agent-facing interface to Berserk observability, letting LLMs answer complex questions through pre-verified KQL tools — no KQL authoring required.
Infrastructure Discovery & Inventory
List containers, services, hosts, and metrics with log/metric breakdowns
Map containers to host VMs, inspect live schema, and explore unknown data sources
Resource & Performance Monitoring
Top containers by CPU/memory, per-host CPU load and memory usage
Berserk query engine latency (p50/p95/p99)
Log & Error Analysis
Error counts grouped by service, recent log lines for a specific service
Run arbitrary KQL queries as an escape hatch (
search)
SRE Tools
Error rate over time, host headroom (CPU/memory side-by-side), ingest health, service health rollup, top repeated error messages
SOC Tools
High-severity logs, log volume spike detection, newly first-seen services, persistently repeated errors, full incident timeline for a service
Claude Code Observability (requires Claude Code logs shipped to Berserk)
Recent activity, session rollups, tool-use histogram, failed tool results, full-text search across message/tool bodies
Custom Query Persistence
Save verified KQL queries as named reusable tools, list saved queries, run them deterministically
Automated Source Onboarding
Queue new services/metrics for automated KQL generation via an LLM-powered parser factory (free/local → paid model ladder)
Check discovery job status; auto-generated query packs are validated before saving
Role-Based Access
Filter tool visibility and inject role-specific primers for SRE, SOC, Claude Code, or Ops roles
Auditing
Amendments log tracks all saved query creations and updates for full auditability
Allows posting summaries and change logs from automated telemetry discovery and query authoring workers to a Discord channel.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@berserk-mcpshow top CPU consumers for the last hour"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
berserk-mcp
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, orsre_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-18over 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 forclaude_desktop_config.jsonandclaude mcp addrecipes.MCP compatibility baseline. The stable default remains
2025-06-18stdio. Additive2026-07-28MCP features are available only when explicitly enabled withBERSERK_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 installanything beyond the package itself. (The optional LLM parser factory usesurllib. 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
bzrkCLI 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
bzrkCLI. 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_checkandmodel_drift_historyclassify a canaried model's tool-routing accuracy over time against a calibrated noise band, plus a--drift-reportCLI 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 addsinvestigate_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), anagentparameter 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-runcanonloom-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
bzrkoutput, 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:
Role lanes — each agent sees only the tools its job needs
Discovery queue and auto-KQL worker — new telemetry sources onboard with no manual query-writing
Amendments log — every
save_querywrite is tracked, so a worker can post changelogs and keep the query store auditable
Approach | Result |
Berserk web UI / | 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 + | ✅ core | reuses |
Token auth, profiles | ✅ core | reuses ( |
MCP surface for LLMs / agents | — | ✅ |
General-purpose chat agent (web UI | ✅ — 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) | — | ✅ |
Role primers injected at | — | ✅ KQL rules, thresholds, routing guidance per lane |
Telemetry-shape discovery | partial ( | ✅ |
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 | ✅ |
Automated source onboarding | — | ✅ |
LLM parser factory — detect a new source, auto-author + verify a KQL query pack | — | ✅ |
Query changelog / amendments log | — | ✅ every |
Two-lane cost model (cheap default · on-demand | — | ✅ tool descriptions + annotations make this safe |
KQL-injection guards on free-text inputs | n/a (humans) | ✅ service-name allowlist · |
Trace/span analysis — find slow/failed traces, reconstruct a span tree with correlated logs | — | ✅ |
Model-behavior monitoring — detect provider changes and routing-quality regressions via scored canary and fingerprints | — | ✅ |
Knowledge-artifact lifecycle pipeline (source URL → validated skill artifact) | — | ✅ |
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
hermesendpoint — 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 |
| 93% | 98% | 4.2s / 4.7s | $0.0114 (never caches) |
| 93% | 93% | 7.3s / 20.8s | $0 (promotional pricing, not durable) |
| 88% | 93% | 3.6s / 12.7s | $0.0003 (caches 5.5x) |
| 83% | 90% | 0.76s / 1.5s | $0.00056 (caches 10x) |
| 78% | 90% | 1.2s / 3.2s | n/a — local candidate |
| 63% | 85% | 1.6s / 4.0s | $0.0005 |
mock keyword-match baseline | 65.9% | — | — | — |
| 7% | 63% | — | free / 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-sabascores 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
ops23
100%
sre32
96%
soc31
95%
claude46
89%
all(no role set)74
80%
The penalty at
allis not raw tool count. It is cross-lane competitor contamination: aclaude_*prompt loses to a similarly-worded tool from the SRE or core lane (for exampleclaude_searchlosing tosearch). SettingBERSERK_MCP_ROLEremoves 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
opsand 12K atsre, 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" --> UserTwo things worth knowing about this diagram:
The bearer token never enters this code.
bzrkowns 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.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" .-> ORHow 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 |
| Gets | Typical agent |
SRE |
| Core tools + SRE tools (error rate, host headroom, ingest health, service health, top errors) | On-call Slack bot, editor assistant |
SOC |
| Core tools + SOC tools (high-severity logs, log spike, new services, repeated errors, incident timeline) | Security monitoring agent |
Claude Code |
| Core tools + Claude telemetry, AI spend, feature economics, data quality, and governed harness recommendations | Developer workflow and AI FinOps assistant |
Ops |
| All tools (full visibility) | Operator shell, admin scripts |
Default |
| 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_discoveryinstead 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 |
| Containers currently sending metrics (with sample counts). |
| Containers ranked by CPU %. Use for container-specific questions; for host CPU use |
| Containers ranked by memory (MB). Use for container-specific questions; for host memory use |
| ERROR-level log counts grouped by service. |
| All services/sources, with log vs metric breakdown. |
| All hosts reporting telemetry, by record count. |
| Per-host CPU (1-minute load average). Default for ambiguous whole-machine CPU questions. |
| Per-host memory used (GB). Default for ambiguous whole-machine memory questions. |
| Which host/VM each container runs on (join key for container↔host questions). |
| Recent log lines for one service. |
| Live tables + column schema introspection. |
| Every metric name being ingested, with counts (discovery). |
| Field metadata (type, cardinality, representative values) via Berserk's native |
| 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. |
| Berserk query engine latency percentiles (p50/p95/p99 in µs). |
| Run arbitrary KQL (escape hatch). Static validation runs before execution in the default |
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 |
| Error log events by service grouped per minute — "is the error rate climbing?" |
| Fixed decision-tree root-cause walk for an elevated error rate — errors_by_service → correlated log-spike → failing traces, one hop per call. |
| CPU load and memory by host — "which VM is saturated?" |
| Berserk ingest lag and dropped data — "is observability lagging?" |
| Full health summary for one named service: event volume, error count, log/metric split, last seen. |
| Most-repeated error messages by service — "what error should I investigate first?" |
| Statistical service-volume anomaly detection using zero-filled series. |
| Native trend fit for an allowlisted host gauge; refuses weak forecasts. |
SOC tools (soc lane only)
Tool | What it answers |
| Recent CRITICAL/FATAL log lines with service and message text. |
| Services with the largest minute-level log bursts — "anything spiking?" |
| Recently first-seen services and sources — "what is new?" |
| Error messages that repeat persistently — probes, loops, stuck processes. |
| Full incident timeline for one named service: timestamps, severity, metric names, message snippets. |
| Statistical service-volume anomaly detection using zero-filled series. |
| Meaning-based log search when semantic indexing is enabled. |
| 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 |
| Recent Claude Code events — type, role, model, tool names, error flag. |
| Sessions rollup — event counts, first/last seen, assistant turns, tool turns, error count. |
| Tool-use histogram — how many times each tool (Bash, Edit, Read, …) was called. |
| Failed tool results with message snippets. |
| Full-text search across Claude Code message and tool bodies. |
| 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. |
| Flags sessions that repeat the same tool/target, retry the same error, or oscillate between calls. |
| Heuristic model-tier fit: frontier model on trivial work, or cheap model on complex/repetitive work. Not a billing statement. |
| Token burn per session and progress unit, using exact usage attributes when present and a labeled estimate otherwise. |
| 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 |
| One session's timeline: contiguous tool phases with error counts, activity gaps over 5 minutes, cumulative burn, and a loop verdict. |
| Cross-session patterns: most common tool sequences, error hotspots by tool+target, top-decile burn-per-target sessions. |
| Token classes, public API-equivalent spend, cache ratio, trends, attribution, and pricing coverage grouped by business or technical dimension. |
| Planned/actual developer hours and AI budget/spend, completion forecast, repositories, agents, harnesses, and delivery outcomes for one feature. |
| Feature and repository economics within one project, including unattributed spend and data-quality coverage. |
| Evidence for expensive models, operations, retries, loops, cache misses, context growth, and agent fan-out. |
| Deterministic, stable-ID harness amendments with confidence, risk, validation window, and rollback criteria. |
| Append-only approval, rejection, or deferral audit record. Owners use a deployment-scoped HMAC pseudonym; rationale is stored as a hash. |
| Matched before/after harness comparison with keep, rollback, no-change, or insufficient-evidence verdict. |
| Portfolio, project, or feature summary as readable Markdown plus versioned structured JSON. |
| 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_checkgroups tool calls by session. It reports the repetition ratio, the top repeated call, the error-retry count, and a verdict:healthy,some-repetition, orlikely-looping.claude_model_fitmaps 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_burnusesclaude.tokens_inputandclaude.tokens_outputwhen present. When they are absent, it falls back per session tobody 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-reportruns 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].flagleaves 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.offdisables 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 queries visible to the current role. Check here before authoring new KQL. |
| Run a saved query by name — deterministic, no KQL authoring. |
| 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-nativesre/azuresre/onprem-ad-healthsoc/endpoint-identitychange-management/ansiblescom
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=trueThe 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 |
| Queue a newly-added service or metric for automated onboarding. Validates the source exists in Berserk before accepting. |
| 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 |
| Search-by-intent over the full tool catalog. Returns the best-matching candidates with their complete |
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 |
| Highest-duration root spans in the time window — "what's slow?" Entry point before |
| Spans whose status indicates an error — "which requests failed?" Entry point before |
| Full breakdown of one trace by |
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:
durationis a dynamic-typed column. Berserk's KQL engine rejectssort by durationdirectly.trace_find_slowcasts it withtoint(duration)before sorting.Not every row sharing a
trace_idis a span. Other correlated telemetry — for example a log row — can carry the sametrace_id/span_idwith a nullspan_name.trace_analyzefilters toisnotnull(span_name), and sorts bystart_timeso 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 |
| 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. |
| Score and fingerprint history for one canaried model over time. Use after |
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 againstdeepseek-v4-flashon 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=3measured ~$0.08 and 7.5–8.5 minutes per model, per run (deepseek-v4-flash, 2026-09-01). SetBERSERK_MCP_CANARY_REPEATSto 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, foreverrequest_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.
sregets a health summary,socgets an incident timeline,claudegets a health rollup, andmetrickind gets a drilldown aggregation.Calls
save_queryto verify and persist the result.Updates
known_sources.jsonso the same source is never re-queued.Posts a summary of completed and failed jobs to Discord, if
BERSERK_DISCORD_ALERT_SECRETis 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:
Tags the entry
action=generated(pipeline-authored),action=updated(a human save to an existing name), oraction=created(a human save to a new name).Appends a timestamped entry to
amendments_log.json, with the name, description, KQL preview, role, and action.Reads and formats a changelog on the next
--workerrun, 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 |
|
| The bridge's alert endpoint. |
| unset | Shared secret sent as |
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_queryverifies 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 towardsre_error_ratefor 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 withsre_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, andsoc_repeated_errorsin 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")andclaude_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.mdor a system prompt configured.) The agent callsrequest_discovery(service="haproxy", role_hint="sre"). The discovery worker runs overnight. It authors and savessre_haproxy_service. The next morning,run_savedanswers 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-minior 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
bzrkCLI, installed and authenticated (bzrk -P <profile> search "..."must work). The bearer token lives inbzrk's own config. berserk-mcp never reads or stores it.(Optional) A running
canonloom-serverinstance, only if you use thecanonloom_*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=localProfiles. 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 retryFor 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.pySet the role in your shell or .env:
BERSERK_MCP_ROLE=sre claude mcp add berserk-q -- berserk-mcpAny 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 thandeepseek-chatthanks to real prompt caching — verified against actual billedusage.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
searchandsave_query, or as an escalation tier for cases a cheaper model's own routing confidence flags as uncertain (seeevals/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 testsThe 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_servicesuses a24h agodefault window with a shard-field filter, returning full results in about 28 seconds against real data volume.sre_host_headroomreports memory in GB, with an explicitunitcolumn distinguishing it from the CPU load-average rows — matchinghost_memory's units.The
trace_*tools (v1.14.0) sort correctly:trace_find_slowcastsdurationto an integer before sorting, andtrace_analyzeorders spans bystart_time. See Trace tools above.claude_token_burn,claude_loop_check, andclaude_model_fit(v1.14.1) parse realbzrk --jsonoutput correctly, including itsTables[0].rows/Tables[0].schema.columnsshape. 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-mcpA 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 toolsbzrk_query_perfBerserk Query PerformanceARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. |
TDQS
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.
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.
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.
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.
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.
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 ErrorsARead-onlyIdempotent
Claude Code tool errors — failed tool results (is_error=true) with a body snippet. Default 6h.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. |
TDQS
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.
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.
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.
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.
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.
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 ActivityARead-onlyIdempotent
Recent Claude Code activity (timestamp, type, role, model, tool names, error flag), newest first. Default window 1h.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. |
TDQS
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.
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.
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.
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.
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.
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_searchClaude Code: Full-Text SearchARead-onlyIdempotent
Full-text search across Claude Code message and tool bodies for a substring. Default 6h.
| Name | Required | Description | Default |
|---|---|---|---|
| term | Yes | substring to find; may not contain quotes, pipe, backslash, or backtick | |
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, openWorldHint, and non-destructive. The description adds 'Default 6h', which implies a default time window for the 'since' parameter, but does not disclose other behaviors like result ordering, limits, or pagination. Value-add is moderate.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with no extraneous information. Everything is front-loaded: purpose and a key behavioral default. Highly efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a search tool with many siblings and no output schema, the description is adequate but minimal. It covers purpose and a default but omits return format, pagination, result count, or error scenarios. Annotations fill some gaps but not fully.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with descriptions for both 'term' and 'since' parameters. The description adds implicit default for 'since' (6h), which is not in the schema. This provides additional practical guidance beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it performs full-text search across 'Claude Code message and tool bodies for a substring', which is specific and distinct from sibling tools like 'search' or 'claude_errors'. The verb 'search' and resource are explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance on when to use this tool vs alternatives (e.g., 'search', 'claude_errors'). The description mentions 'Default 6h' but does not explain optimal contexts or exclusions. Lacks explicit when-to-use or when-not-to-use advice.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
claude_sessionsClaude Code: SessionsARead-onlyIdempotent
Claude Code sessions rollup: events, first/last seen, assistant turns, tool turns, and error count per session. Default 6h.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. |
TDQS
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.
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.
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.
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.
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.
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 HistogramARead-onlyIdempotent
Claude Code tool-use histogram — how many times each tool (Bash, Edit, Read, ...) was used. Default 6h.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. |
TDQS
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.
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.
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.
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.
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.
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 MapARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. |
TDQS
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.
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.
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.
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.
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.
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 SchemaARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. | |
| service | No | optional: limit to one service.name |
TDQS
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.
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.
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.
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.
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.
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 StatusARead-onlyIdempotent
List pending and completed discovery jobs for new services or metrics.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
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.
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.
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.
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.
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.
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 ServiceARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. |
TDQS
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.
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.
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.
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.
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.
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 LoadARead-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).
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. |
TDQS
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.
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.
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.
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.
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.
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 MemoryARead-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).
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. |
TDQS
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.
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.
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.
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.
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.
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 ContainersARead-onlyIdempotent
List all containers currently sending metrics to Berserk (with sample counts).
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. |
TDQS
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.
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.
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.
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.
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.
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 HostsARead-onlyIdempotent
All hosts reporting telemetry, by record count.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. |
TDQS
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.
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.
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.
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.
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.
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 MetricsARead-onlyIdempotent
List every metric name currently being ingested, with sample counts + last-seen. Use to DISCOVER what telemetry exists before writing a search query.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. |
TDQS
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.
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.
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.
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.
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.
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 QueriesARead-onlyIdempotent
List previously-saved custom queries (name + description). For a non-standard question, CHECK HERE FIRST before writing new KQL.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
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.
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.
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.
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.
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.
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 ServicesARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. |
TDQS
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.
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.
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.
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.
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.
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 LogsARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. | |
| service | Yes | service.name value |
TDQS
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.
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.
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.
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.
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.
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 DiscoveryAIdempotent
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'.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. | |
| metric | No | metric name to integrate | |
| service | No | service.name to integrate | |
| role_hint | No | optional target role: sre, soc, claude, ops | |
| requested_by | No | optional requester label |
TDQS
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.
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.
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.
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.
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.
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 QueryARead-onlyIdempotent
Run a previously-saved query by name (see list_saved). Deterministic - no KQL authoring.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | saved query name | |
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. |
TDQS
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.
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.
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.
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.
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.
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 QueryAIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| kql | Yes | KQL starting with 'default | ...' | |
| name | Yes | short snake_case name | |
| roles | No | optional role(s) this query serves: sre, soc, claude, ops | |
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. | |
| description | Yes | what the query answers |
TDQS
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.
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.
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.
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.
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.
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 IntrospectionARead-onlyIdempotent
Show Berserk tables + column schema (live introspection).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
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.
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.
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.
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.
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.
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.
searchRun KQLARead-onlyIdempotent
Run an arbitrary Kusto/KQL query against the Berserk table. Use when the other tools do not fit; once it works, persist it with save_query.
| Name | Required | Description | Default |
|---|---|---|---|
| kql | Yes | KQL starting with 'default | ...' | |
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already provide readOnlyHint, openWorldHint, idempotentHint, destructiveHint. Description adds context about targeting the Berserk table and persistence hint, but does not significantly extend behavioral disclosure 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.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, no wasted words. Front-loaded with purpose and usage guidance. Perfectly concise.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (2 params, no output schema), the description covers purpose, usage, and post-action hint. Lacks details on output format or error scenarios, but acceptable for a straightforward KQL runner.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents both parameters adequately. Description does not add further meaning about kql format or since values beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The title 'Run KQL' and description clearly state the action (run arbitrary KQL query) and resource (Berserk table). It distinguishes from siblings by positioning it as a fallback tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says 'Use when the other tools do not fit' and advises to persist results with save_query. Lacks explicit 'when not to use' but sufficient for a fallback tool.
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 LogsARead-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'.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. |
TDQS
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.
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.
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.
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.
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.
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 SpikeARead-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'.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. |
TDQS
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.
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.
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.
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.
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.
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 ServicesARead-onlyIdempotent
SOC view of services ordered by first-seen time. Use for 'what is new', 'anything first-seen', or 'did a new source appear'.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. |
TDQS
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.
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.
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.
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.
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.
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 ErrorsARead-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'.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. |
TDQS
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.
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.
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.
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.
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.
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 TimelineARead-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'.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. | |
| service | Yes | service.name value |
TDQS
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.
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.
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.
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.
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.
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 RateARead-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'.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. |
TDQS
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.
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.
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.
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.
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.
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 HeadroomARead-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'.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. |
TDQS
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.
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.
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.
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.
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.
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 HealthARead-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'.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. |
TDQS
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.
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.
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.
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.
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.
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 HealthARead-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'.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. | |
| service | Yes | service.name value |
TDQS
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.
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.
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.
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.
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.
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 MessagesARead-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'.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. |
TDQS
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.
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.
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.
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.
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.
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 CPUARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. |
TDQS
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.
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.
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.
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.
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.
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 MemoryARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Time window e.g. '15m ago', '1h ago', '2d ago'. |
TDQS
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.
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.
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.
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.
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.
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
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).
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.
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.
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
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
Find best-fit tools for any problem, vetted for prompt-injection risk before your agent trusts them
Query your team's drift, vulnerability, and upgrade data from any AI assistant. OAuth 2.1, 51 tools.
Runtime permission, approval, and audit layer for AI agent tool execution.
The grounded data layer for any LLM: governed SQL, metrics, lineage and catalog over your data.
Related MCP Servers
- AlicenseBqualityDmaintenanceEnables 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.82Apache 2.0
- AlicenseAqualityDmaintenanceEnables LLMs to query telemetry data via the Spyglass AI agent, providing intelligent insights about application performance, errors, and bottlenecks.1MIT
- AlicenseNot gradedqualityDmaintenanceEnables 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.1614MIT
- AlicenseNot gradedqualityDmaintenanceEnables 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.5MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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