内容
# berserk-mcp
[](https://github.com/ssimonsen0202/berserk_mcp/actions/workflows/ci.yml)
MCP 服务器,允许 LLM 回答 Berserk 可观测性问题,通过**调用工具**而非手动编写 KQL。
> **为什么这很重要:** 当你给模型一个原始查询语言时,它会猜测 — 表名、字段名错误,聚合操作细微错误 — 你为重试付费。每个工具都封装了一个**已验证**的 Kusto/KQL 查询,因此模型选择意图(`top_cpu`、`errors_by_service`、`sre_host_headroom`),查询已固定。确定性是关键。实际上,这使得即使小型/廉价模型也能可靠地回答可观测性问题。
- **与 Claude Desktop、Claude Code 和任何 MCP 客户端配合使用。** 支持 MCP 协议版本 `2025-06-18`,通过 stdio(newline-delimited JSON-RPC 2.0)。所有必需方法 — `initialize`、`notifications/initialized`、`ping`、`tools/list`、`tools/call` — 都已实现,严格的信封验证和对抗性回归测试。参见 [连接到客户端](#connect-it-to-a-client),获取 `claude_desktop_config.json` 和 `claude mcp add` 示例。
- **零依赖。** 纯 Python 标准库 — 无需 `pip` 安装依赖(可选的 LLM 解析器工厂使用 `urllib`,仍然无第三方依赖)。
- **小且可审计。** 五个小型标准库模块:`berserk_mcp.py`(MCP 服务器)、`parser_factory.py`(可选的 LLM 解析器生成器)、`agent_analytics.py`(Claude Code 分析)、`secret_scan.py`(机密检测/删除)和 `ingestion_advisor.py`(目录支持的遥测差距分析)。易于阅读、审计和供应商。
- **跨平台。** 在安装了 `bzrk` CLI 的任何地方运行,包括 Windows。
- **安全构造。** 固定查询、自由文本工具输入验证、无 `shell=True`,Berserk token 从未接触过此代码。
- **自我扩展(1.7 新增)。** 可选的[解析器工厂](#parser-factory-llm-generated-query-packs)检测 Berserk 中新到达的源,并使用 LLM 编写、执行-验证并保存 KQL“查询包”— 仿照 Microsoft Sentinel 的 [ASIM 解析器 AI 代理](https://learn.microsoft.com/en-gb/azure/sentinel/normalization-create-parsers-ai-agent)。廉价优先提供商梯队,硬性运行失控安全阀,生成的查询永远不会覆盖人工查询。
> ## ⚠️ 免责声明 — 请阅读
>
> 这是一个**非官方、社区建设**的项目。它与 Berserk 项目或其维护者**无关、未赞助、未背书或支持**。
>
> 按照**原样提供,不保证任何责任**,因使用、结果、停机时间、数据丢失、成本而产生的任何后果(参见 [LICENSE](LICENSE))。您自行承担风险,将其指向生产 Berserk 环境。 如果您指向生产 Berserk 环境,请自担风险。
>
> 错误、功能请求和关于**此服务器**的问题:请在此处提出问题。关于 Berserk 本身的问题请到 Berserk 项目 — 不是我们。
## 为什么存在
**Berserk** 是一个自托管的可观测性后端:它通过 OTLP 收集日志、指标和跟踪,并允许您使用 Kusto 风格的语言(KQL)通过 `bzrk` CLI 或其 Web UI 查询它们。它是存储和查询引擎,假设有人已经了解 KQL。
**空白。** 原始查询语言是 LLM 确实不擅长的东西。指向模型 `bzrk`,它会发明表名、误输入字段名,并重试消耗令牌。
显而易见的解决方案 — 将模式粘贴到提示中、少量 KQL 示例 — 被首先尝试并**失败**:模型不断猜测。硬编码查询也不理想。
**berserk-mcp 新增功能。** 它是 Berserk 前面的一个翻译层,为可观测性**意图**公开 MCP 工具(`top_cpu`、`errors_by_service`、`sre_service_health`等)。每个工具都封装了一个已验证的查询,因此模型永远不会编写 KQL — 它选择意图和时间窗口。它**不**取代 Berserk 的存储、查询引擎或 UI;它使它们对**代理可访问且在小型/廉价/本地模型上可靠**。
除了固定工具外,服务器还添加了三个默认 Berserk 中不存在的层:
1. **角色通道** — 工具可见性按工作职能过滤,以便每个代理只看到它需要的工具
2. **发现队列 + 自动 KQL 工作线程** — 新遥测源的自动上线
3. **修订日志** — 每个 `save_query` 写入都被跟踪,以便工作线程可以发布变更日志并保持查询存储可审计
| 方法 | 结果 |
|---|---|
| Berserk 网页 UI / `bzrk` CLI | 适用于了解 KQL 的人类;代理不可用。 |
| 将 LLM 指向原始 CLI + 模式文档 | 不可靠 — 模型猜测表/字段名并为重试付费。 |
| 通用“文本到 KQL”MCP | 仍然**编写**查询 → 相同的猜测问题,一层向上。 |
| **berserk-mcp** | 固定、验证的查询 → 确定性答案,即使来自 7B 局部模型。 |
---
## 与默认 Berserk 相比新增功能
Berserk 本身是一个优秀的面向人类可观测性后端。此服务器不替换任何功能 — 它位于旁边并添加面向代理的表面。具体来说:
| 功能 | 默认 Berserk | berserk-mcp |
|---|---|---|
| 收集 OTLP 日志/指标/跟踪 | ✅ 核心 | 复用 |
| KQL 查询引擎 + 存储 | ✅ 核心 | 复用(只读) |
| 人类使用的 Web UI + `bzrk` CLI | ✅ 核心 | 复用 |
| 令牌身份验证、配置文件 | ✅ 核心 | 复用(`bzrk`持有令牌) |
| **LLM / 代理的 MCP 接口** | — | ✅ |
| **无需编写 KQL 即可回答常见问题** | 需要正确的 Kusto → 小模型失败 | ✅ 固定验证工具 |
| **基于角色的工具过滤**(SRE / SOC / Claude / Ops 通道) | — | ✅ `BERSERK_MCP_ROLE` 环境变量 |
| **角色启动器**在 `initialize` 时注入 | — | ✅ KQL 规则、阈值、路由指南按通道 |
| **遥测形状发现** | 部分(`.show tables`) | ✅ `list_metrics` · `discover_schema` · `container_hosts` |
| **自定义查询持久性**为命名、可重用的工具 | UI 有查询库,但 Berserk 文档没有 API 或 CLI 命令以编程方式创建、列出或共享查询 | ✅ `save_query`(验证后持久化)→ `run_saved`,代理可读 |
| **自动源上线** | — | ✅ `request_discovery` → 工作线程 → 已保存查询,无需 KQL 编写 |
| **LLM 解析器工厂** — 检测新源,自动编写 + 验证 KQL 查询包 | — | ✅ `detect_new_sources` · `generate_parser` · `run_discovery_worker` · `review_generated`(ASIM 代理样式;见下文) |
| **查询变更日志 / 修订日志** | — | ✅ 每个 `save_query` 写入被跟踪;工作线程发布 Discord 差异 |
| **两通道成本模型**(廉价默认 · 按需 `@deep`) | — | ✅ 工具描述 + 注解使此功能安全 |
| **KQL 注入防护**在自由文本输入上 | 无(人类) | ✅ 服务名称允许列表 · `claude_search` 拒绝列表 |
| **跟踪/跨度分析** — 查找慢/失败的跟踪,重建具有相关日志的跨度树 | — | ✅ `trace_find_slow` · `trace_find_errors` · `trace_analyze`(v1.14.0;见 [跟踪工具](#trace-tools-all-lanes)) |
---
## 架构
### 通道之间的通信以及与 Berserk 的通信
```mermaid
flowchart TB
classDef user fill:#0d1117,stroke:#58a6ff,color:#c9d1d9
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 berserk fill:#1d1d3a,stroke:#a371f7,color:#c9d1d9
classDef store fill:#0d1117,stroke:#8b949e,color:#c9d1d9,stroke-dasharray:3 3
User([用户 · Slack 机器人 · 代理框架]):::user
subgraph H["MCP 主机 (Claude Code · Claude Desktop · LangChain · ChatOps 机器人)"]
direction TB
Cheap["⚡ 默认通道\n廉价 / 本地模型\ngpt-4.1-mini · Qwen2.5-7B · Haiku\n仅选择工具 + 时间窗口"]:::cheap
Deep["🧠 @deep / 调度通道\n能力模型\nsonnet · GPT 类\n编写 + 验证 KQL"]:::deep
end
subgraph M["berserk-mcp (stdio · JSON-RPC 2.0 · 零依赖 Python 标准库)"]
direction TB
RoleFilter["角色过滤器 BERSERK_MCP_ROLE=sre|soc|claude|ops|all\n通道级别工具列表过滤\n初始化时注入启动器"]:::mcp
Tools["固定工具 — 验证的 KQL\ntop_cpu · errors_by_service · host_cpu\nlogs_for_service · sre_* · soc_* · claude_*"]:::mcp
Disc["发现工具\nlist_metrics · discover_schema\ncontainer_hosts · list_services · schema"]:::mcp
Learn["学习循环\nsearch → save_query → run_saved\n验证后持久化 · 修订日志 · 500 封顶"]:::mcp
Queue[("discovery_queue.json\nknown_sources.json\namendments_log.json")]:::store
Store[("learned.json\n~/.config/berserk-mcp")]:::store
end
Worker["发现工作线程\n排干队列 · 编写 KQL · 发布 Discord\n每天运行一次"]:::deep
Bzrk["bzrk CLI\n令牌仅存在于 bzrk 的 0600 配置中\nMCP 从未读取或存储它"]:::berserk
subgraph B["您的 Berserk 实例"]
direction TB
Gw["Berserk 网关 · KQL 引擎"]:::berserk
Tbl[("默认表\nOTLP 日志 · 指标 · 跟踪")]:::berserk
end
User -- "自然语言问题" --> Cheap
User -- "@deep 提示 · 一天一次的 cron" --> Deep
Cheap -- "tools/call — 基于角色过滤的工具" --> RoleFilter
RoleFilter --> Tools
RoleFilter --> Disc
RoleFilter --> Learn
Deep -- "发现 → 搜索 KQL → save_query" --> Learn
Deep -- "request_discovery" --> Queue
Queue --> Worker
Worker -- "save_query per source" --> Learn
Worker -- "Discord 摘要" --> User
Tools -. "argv 列表(无 shell)" .-> Bzrk
Disc -. "argv 列表(无 shell)" .-> Bzrk
Learn -. "验证查询后持久化" .-> Bzrk
Learn <-->|持久化 · 重用| Store
Bzrk -- "只读 KQL 通过身份验证令牌" --> Gw
Gw --> Tbl
Learn -. "已保存的查询可供 Cheap 永久重用" .-> Cheap
```
三件图示内容:
1. **令牌从未进入此代码。** `bzrk` 在其自己的 0600 配置中拥有它;MCP 通过 argv 列表(无 shell,无令牌进入进程内存,无日志)输出。
2. **学习循环闭环回到廉价通道。** 支付有能力的模型一次来编写 + 验证查询;廉价通道通过 `run_saved` 免费运行它。
3. **工作线程是自动化桥梁。** 当 `request_discovery` 排队新源时,工作线程自主排干 — 发现、编写 KQL、保存 — 无需操作员 KQL 编写。
---
## 角色通道
设置 `BERSERK_MCP_ROLE` 以限制代理看到的内容。过滤器在 MCP 协议级别应用 — 不相关的工具从未出现在 `tools/list` 中,因此不能意外调用或注入上下文。
| 角色 | `BERSERK_MCP_ROLE` | 获取 | 典型代理 |
|---|---|---|---|
| SRE | `sre` | 核心工具 + SRE 工具(错误率、主机余量、摄入健康、服务健康、顶部错误) | 上线 Slack 机器人、编辑助手 |
| SOC | `soc` | 核心工具 + SOC 工具(高严重性日志、日志峰值、新服务、重复错误、事件时间线) | 安全监控代理 |
| Claude Code | `claude` | 核心工具 + Claude Code 遥测工具(会话、工具直方图、错误、全文本搜索、循环/模型拟合检查) | 开发工作流助手 |
| Ops | `ops` | 所有工具(完全可见性) | 操作员 shell、管理员脚本 |
| 默认 | `all`(或未设置) | 所有工具 | 开发、评估 |
### 角色启动器
当一个通道连接时,服务器将 Markdown 启动器注入 MCP `initialize` 响应启动器携带:
- **工具路由表** — 每个意图首先要使用的工具
- **升级阈值** — 例如 CPU 负载 > 2.0,内存 > 85%,错误率 > 10/min,摄入延迟 > 30 秒
- **KQL 编写规则** — 时间窗口默认值、字段名称约定、聚合模式
- **发现流程指导** — 何时调用 `request_discovery` 而不是编写临时 KQL
这意味着代理配置中不需要提示工程;路由知识随服务器一起传输。
启动器位于 `primers/<role>.md` 服务器文件旁边(或 `BERSERK_MCP_PRIMERS_DIR` 如果设置)。`all` / `ops` 角色不接收启动器 — 他们直接从工具描述中路由。
---
## 工具
### 核心工具(所有通道)
| 工具 | 它回答的问题 |
|---|---|
| `list_containers` | 当前发送指标的容器(带有样本计数)。 |
| `top_cpu` | 按 CPU % 排名的容器。对于容器特定问题,请使用 `host_cpu`。 |
| `top_memory` | 按内存(MB)排名的容器。对于主机内存问题,请使用 `host_memory`。 |
| `errors_by_service` | 按服务分组的 ERROR 级日志计数。 |
| `list_services` | 所有服务/源,日志 vs 指标分解。 |
| `list_hosts` | 报告遥测的所有主机(报告 HermesRuntime、OpenClaw、ESXiv 等)。 |
| `host_cpu` | 每主机 CPU(1 分钟负载平均值)。默认用于模糊的整机 CPU 问题。 |
| `host_memory` | 每主机内存使用量(GB)。默认用于模糊的整机内存问题。 |
| `container_hosts` | 每个容器运行在哪个主机/VM 上(容器↔主机问题的连接键)。 |
| `logs_for_service` | 一个服务的最近日志行。 |
| `schema` | 实时表 + 列模式自省。 |
| `list_metrics` | 正在收集的每个指标名称,带有计数(发现)。 |
| `discover_schema` | 样本行以了解未知源的 `resource` / `attributes` 形状。 |
| `bzrk_query_perf` | Berserk 查询引擎延迟百分比(µs 中的 p50/p95/p99)。 |
| `search` | 运行任意 KQL(逃脱舱;`save_query` 一旦有效)。 |
每个查询工具都有一个可选的 `since` 参数(`"15m ago"`、`"1h ago"`、`"2d ago"`等),每个工具都有一个合适的默认值。
**主机与容器:** `host_cpu` / `host_memory` 报告每个**主机**;`top_cpu` / `top_memory` 报告每个**容器**。描述相互引用以便模型选择正确的工具。对于模糊的整机问题(“什么东西正在占用服务器?”),始终优先使用主机工具。
### 跟踪工具(所有通道)
| 工具 | 它回答的问题 |
|---|---|
| `trace_find_slow` | 时间窗口内持续时间最长的根跨度 — “什么慢?”进入 `trace_analyze` 之前。 |
| `trace_find_errors` | 状态指示错误的跨度 — “哪些请求失败了?”进入 `trace_analyze` 之前。 |
| `trace_analyze` | 通过 `trace_id` 分析一个跟踪:时间顺序的每个跨度,加上共享相同 `trace_id` 的相关日志行。 |
1.14.0 版添加了分布式跟踪分析,移植自单独的 TypeScript MCP 原型 (`ssn-bzrk`),该原型探索了相同的问题空间。字段名称最初是根据与此表的 `<signal>_name` 约定进行猜测的,借鉴了表的名称(指标的 `metric_name`,日志的 `body` / `severity_text`)。在无法访问 Berserk 查询网关的情况下,名称被猜测。
**那次停机证明是真实的,而不是网络故障:** Docker Compose Berserk 部署在测试期间完全宥。被测试的 Docker Compose Berserk 部署已完全宥。`nursery` 的容器内存限制对于其实际工作集来说太紧了,几个 OOM-kill 崩溃循环导致整个堆栈在之后短时间停止并从未重新启动。通过 `docker inspect` / 内核 OOM 日志条目进行根本原因分析,修复了将内存限制粗略增加一倍以匹配观察到的用法,堆栈被清理后重新启动。如果您的自托管 Berserk 静默,`docker inspect <container> --format '{{.State.OOMKilled}}'` 加 `journalctl -k | grep -i oom` 是快速区分 OOM 崩溃循环和网络/身份验证问题的好方法。
**集群恢复后,这些工具在同一集群中进行了现场验证**,与下面每个 SRE / SOC 工具一样(参见 [实时验证,不只是单元测试](#live-verified-not-just-unit-tested))。所有六个猜测的字段名称在第一次尝试时都被确认正确 — 此集群确实摄入实时跟踪/跨度数据(Berserk 的内部服务被自我检测;`service=query`,`service=gateway`,`service=ingest` 跨度是实际流动的)。两个实际错误被发现,一个在当前版本中修复。
1. **`duration` 是一个 *动态* 类型列** — Berserk 的 KQL 引擎拒绝直接 `sort by duration`(“不能按动态值排序”)。使用显式 `toint(duration)` 强制转换修复了 `trace_find_slow` 中的问题。
2. **并非所有共享 `trace_id` 的行都是跨度** — 其他遥测(日志行,观察到的实时)携带相同的 `trace_id` / `span_id` 但 null `span_name`。`trace_analyze` 现在过滤到 `isnotnull(span_name)`。按 `timestamp` 排序还会产生错误的跨度排序;切换到 `start_time`,它正确排序。
### SRE 工具(仅 `sre` 通道)
| 工具 | 它回答的问题 |
|---|---|
| `sre_error_rate` | 服务每分钟错误日志事件 — “错误率正在攀升?” |
| `sre_host_headroom` | 主机 CPU 负载和内存 — “哪台虚拟机饱和了?” |
| `sre_ingest_health` | Berserk 摄入延迟和丢弃的数据 — “遥测滞后了吗?” |
| `sre_service_health` | 命名服务的完整健康状况:事件量、错误计数、日志/指标分割、最后看到。 |
| `sre_top_error_messages` | 服务中重复出现的错误消息 — “我应该先调查哪个错误?” |
SOC
工具 |的问题 |
|---|---|
| `soc_high_severity_logs` | 最近的严重日志行,包含服务和消息文本。 |
| `soc_log_spike` | 日志量最大的服务 - "有什么异常?" |
| `soc_new_services` | 最近首次发现的服务和来源 - "有什么新东西?" |
| `soc_repeated_errors` | 持续重复的错误消息 - 探测、卡住的进程。 |
|_timeline` |服务的完整事件时间线:时间戳、严重程度、指标名称、。 |
|crets`服务/类型机密附带首次戳。 值返回。密检测编辑
1.0 版本在 MCP 输出边界添加了一个仅限标准库密扫描每个 `tools 的结果都BERSERK_MCP_REDACT` 进行处理:
- `flag` (默认)保留结果完整,并在检测到机密时添加警告前缀。
- `redact` 用类型化的占位检测到的 `[REED:]`。
- 禁用。
扫描器云/、私钥、承载令通用密码/令牌赋值。 高熵匹配是可选的,因为它容易阳性。 邮件、IP 和 Luhn 验证的是单独可选择的。 `crets` 审计最近的日志主体,但只返回聚合计数和时间戳不会返回匹配的值。 这只保护 MCP 输出。 Berserk密必须在时删除,并且凭证必须。
### Claude(仅 `claude` 通
如果您将 Claude Code 会话日志 Berserk名称 `cl`),会挖掘这些 有关管道阅 [docs-code.md](aude-code.md 工具 | 它回答的问题 |
|---|---|
| `claude_recent` | 最近的 Claude Code 事件 - 类型、角色、模型、工具名称、错误标志。 |
| `claude_sessions` | 会话汇总 - 事件计数、首次/最后一次助手回合回合、 |
| `claude_tools`工具使用图 - (Bash、编辑、读取、...)被调用。 |
|aude_errors 带有消息片段的失败工具结果| `cl` | Claude Code 消息和工具主体的全文搜索。 `claude` |重复相同工具/重试相同错误或在调用之间振荡的会话。 |
|aude_model_fit` | 式模型层适应性:前沿模型用于简单廉用于复杂/。 不是声明。 `cl_burn` | 每个会话单位的令牌消耗,使用确切的使用属性(如果存在)估计值。 |
### 智能
8.1 版本为 `claude` 通道提供只读分析层:
- `_loop_check` 按工具调用,并报告重复比率、顶部重复调用、错误重试计数和 `健康` / `某些 ` 的裁决。
- `_model_fit` 将模型名称映射粒度层(沿`、`中间`、`廉价`)并将其与工具计数、持续时间和循环信号的复杂度代理进行比较。
- `claude_token_burn` 使用 `claude.tokens_input` + `claude.tokens_output`(如果存在),否则回退到每个会话的 `正文字符 4`,计算每个不同工具和推断的文件目标的消耗,并突出显示顶部十分位的消耗。 每个结果有其来源是精确还是估计的。
```bash
berserk-mcp --agent "6h ago"
```
**v1.14.1 修复 — 这三个工具曾经默默地返回零结果,针对真实数据。**
实时验证 `claude_token_burn` 针对实际的 Berserk 输出(2026-07-17)发现了一个影响这三个工具的解析错误: `_json_records()` 只识别裸 JSON 数组或 `{"rowsdata"/"results"/"records": [...]}` 包装器,但实际的 `bzrk --json` 输出被塑造成 `{"Tables": [{"schema": {"columns": [...]}, "rows": [[... ...}` — 行是匹配列顺序的位置数组,而不是字典。 由于该形状未被识别, `_parse_rows` 默默地下降到 jsonl/表解析器,该解析器找不到任何内容,并且每个调用都返回“ Claude Code 事件”,即使存在真实数据 — 没有错误,只是默默地为空。 通过教 `_json_records` 解包 `Tables[0].rows` 以匹配 `Tables].schema.columns` 修复。 确认实时: `claude.tokens_input` / `claude.tokens_output` 是真正的属性名称(不再是猜测),并且 7 天的查询正确查询显示了 5 个会话、精确的计数和一个真正的顶部令会话(一个 1,592 Opus繁重的会话这一点就占了当周 73令 — 而不是循环, `claude_loop_check` 确认 `健康`,只有大转弯)。
### 学习循环工具(所有通道)
| 工具 | 它回答/执行什么 |
|---|---|
| `list_saved` | 列出当前角色可见的已保存查询。 在编写新 KQL请在此 |
| `run_saved` | 按名称运行已保存的查询 - 确定性,无需编写 KQL。 |
| `save | 验证 KQL 查询运行,然后存在名称下(带有可选的角色标签)。 将每次写入记录到修订日志中。 |
### 摄入顾问
1.12.0 版本添加了 `suggest_ingestion`,一个由可编辑的 `ingestion_catalog.json` 知识库支持的跨通道只读工具。 它建议具体的来源,解释每个来源的重要性,命名摄入机制,并标记其成熟度(`turnkey`、`collector-receiver`、`` 或 `manual`)。
已知的:
sre-native`
- `sre/azure`
- `/onprem-ad-health`
- `soc/endpoint-identity`
change-management/ansible`
- `scom`
设置 `check_gap=true将服务提示与实时 Berserk 库存进行比较。 每个建议都被 `存在 `缺失`,并带有匹配的信号或确切的摄入操作。 例如:
```text
suggest_ingestion role_or_usecase=sre/onprem-ad-health check_gap=true
```
AD 路径建议通过 OTel Collector `windowseventlog` 接收器获取 Security、System 和 Directory Service 通道。Ansible 路径使用 `community.general.opentelemetry` 回调。SCOM 显式地 `bridge-required`:它需要只读 REST/API 或仓库 SQL 到 OTLP 桥;顾问并不声称存在本机 SCOM OTel 。
###工具(所有通道)
| 工具 |什么 |
|---|---|
|_discovery` | 为自动新服务或指标到队列中。 在接受之前验证源是否存在erk 中。 |
| `_status` | 列出待处理和已完成的发现作业。 |
---
## 自我扩展:发现 + 学习
固定的工具涵盖了已知的遥测数据。 对于服务器尚未具备工具的数据 - 您刚刚开始发送的日志源 - 一个两阶段的循环手动编辑代码的情况下扩展服务器,同时保持廉价通道的确定性 阶段 1:发现队列
```
QUEUE request_discovery(service="haproxy") → 验证源,队列作业
WORKER discover-worker 排队作业:00 → 按类型编写
SAVE save_query (验证后保存) → 的,命名的查询
REUSE run_saved("sre_haproxy → 廉价模型,免费,永久
```
`request` 在接受作业之前执行一项操作:它list_services` (或 `list_metrics`)源实际上在 Berserk 中可见。 未知的源会被明确错误拒绝,因此队列中永远不会作业。
发现工作器(`discover-worker.py`, cron 运行)会排空队列:
- 为每个角色选择合适的 KQL 模板(`` 获取健康摘要,` 获取事件时间线,`claude` 获取健康汇总,`metric` 类型获取钻取聚合)
- 调用 `save_query` 以验证和保存结果
- 更新 `known_sources.json` 以便永远不会重新排队相同的源
- 在 Discord 中发布已完成和失败作业的摘要
### 阶段 2: 修订和改进
当一个有能力的模型@deep`,一个定时代理,或操作员)通过_query` 改进或纠正现有查询时,服务器:
1. 检测查询名称是否已存在(`updated`为新查询(`action=created`)
2. 将带有名称、描述、KQL 预览、角色和操作的带时间戳的条目追加到 `amendments_log.json` 中
3. 工作器在排空运行中读取并清除此日志,在 Discord 中发布更改日志: `✏️` 用于更新, ` 用于新
**查询存储是可审计的** - 由自主代理进行的每次改进都会在中,无员干预。
预期的劳动(成本效益):
-能力的模型执行少量的的部分** - 发现,编写 + 验证查询, `save_query` 它。 通过两种方式触发:**计划一个检查发现队列的),或**按需** (“ Berserk 中添加了 HAProxy - 添加支持”)。
-价模型利用结果** - 每个已保存的查询都可以通过 `run_saved` 免费重复使用,确定性地。 编写 KQL 是小型模型较弱的一项,因此在此设置了一个强有力的模型作为保障; `save_query` 在保存之前的运行情况。
这样可以扩展,因为**学习的查询生活在 `list_saved `run_saved` 后,而不是作为一流 - 因此您可以学习数十个新源,而不会增加保持廉价模型可靠的路由表面。
---
## 解析器工厂:LLM 生成的
**它解决的问题:** 一种新的服务或日志类型开始发送到 Berserk,但还没有相应的工具。 通常,人类会注意到,使用 `dis` 探索形状,手动编写 KQL,然后 `save_query` 它。 解析器工厂自动化了这个循环。
以微软的 [ 的 ASIM 解析器代理](https://learn/en-gb/azure/sentinel/normalization-create-parsers-ai-agent) 为蓝本:数据 → 生成 KQL → 通过执行验证 → 失败时改进(最多 5 次循环)→ 保留幸存者。 由于 Sentinel 的代理生成存储的 ASIM 解析,而 Berserk 没有存储函数,因此这里的输出是一个 **查询包**:每个源 2-4 个已验证的 `save 条目(概览、错误/时间线视图和指标聚合(如适用- 以后可以无限期重复使用 `run廉价通道上。
AS器 AI(Sentinel)与 berscp 解析器映射:
| ASIM 解析器 AI 代理(Sentinel) | berserk-mcp 解析器工厂 |
|---|---|
| 需求收集 | 发现作业 - 源名称、类型、角色| 源数据采样(`get + 最多 2,000 行) | `build_source_profile`:资源键 + 行样本 + `getschema| 生成 KQL 解析器 | LLM生成 JSON **查询包** |
| 架构验证(`ASimSchema) | 声明的输出列与实际查询输出进行检查 |
| 数据验证(`ASimDataTester`) | 查询被**执行**;必须返回行(窗口在失败前) |
改进循环(5 次 验证器错误反馈给模型,5 次尝试/提供者 |
部署/打包 | 通过现有的 `save_query` 存储(重新验证)持久| | 报告发现作业上;通过 `discovery `review_generated` 可见 |
阶梯。** 生成尝试按顺序 - 免费/本地在失败时才使用昂贵的:
```
hermes免费)→ openai → anthropic
```
每个提供者最多可获得 5 次精炼尝试,并将上一次失败的验证器错误反馈到下一个提示中。 如果提供者未配置(无 API 密钥),则在一次尝试后跳过,而不是烧掉整个 5 次。
**工具:**
| 工具执行什么 |
|---|---|
| `detect` | 扫描 Berserk 中以前从未见过的服务/指标,并可选地检查已知服务的模式漂移(现有服务的新属性键_queue=true` 将新发现的内容加入发现队列。 |
| `generate_parser` | 为一个源同步生成并验证查询包。run_discovery_worker` | 通过管道排 N 个待处理的发现作业。 |
|_generated` | 列出或检查 LLM 生成的已保存查询 - 在信任它们之前进行审计它生成的内容。** 对于新检测haproxy,一次运行会将此发现作业:
```
generate_parser(service="", role_hint="sre")
```
验证的、源前缀的已保存查询(仅保留实际返回行的查询):
```
_overview – 事件量,日志分割,最后一次看到
haproxy_error – 每分钟错误行
haproxy – 按后端分组的请求
都存储 `generated_by: {provider,, job_source}` 并且可以通过 ` name=haproxy_overview` 立在廉价通道上。
**安全性。的 KQL 通过与人类输入相同的 `_KQL_PREFIX_RE` 保护,并且仅在成功执行针对 Berserk 时保存。 生成的查询永远默覆盖人类保存的查询 - 在时,它会保存为 `<name>_gen`。 每个生成的条目都带有 `generated_by: {provider, model, ts, job_source}`,因此 `review_generated` 可以在生产中使用之前对其进行审计。 请参阅 [SECURITY.md](SECURITY.md) 以获取完整的安全威胁模型,包括日志数据馈送到生成提示的间接提示注入风险。
**失控的安全阀。** 自动发现故意有界限,以免其永远阻塞队列或在一次传递中烧毁大量 LLM 令牌 - 实际集群可能有数百个指标:
- **内部指标永远不会自动排队。** `detect_new_sources` 将它们记录在基线中(以便不会重新标记为“新”),但只会排队**服务** - 助手永远不需要每个指标的查询包。
- **每运行服务上限。** 单次 `detect` 传递最多排队 `MAX_PER_RUN` 个新服务(默认为 **5**,可通过 `BERSERK_MAX_AUTOQUEUE` 覆盖);其余的将在后续运行中拾取。
- **每运行排空上限。** `run_discovery_worker` / `--worker` 为每个调用生成最多有界数量的作业( `--max-jobs`,上限为 5),因此大型待处理队列会逐渐排空,而不是一次性全部排空。
- **短暂名称过滤器。** 数字的服务例如,裸作为 `service.name出的更改的数字 ID)将被跳 否则,它们都会显示为”,并将队一个垃圾第一次针对全新 Berserk 运行的 `detect_new_sources` **将基线种子并排0 个**每天第一次,所有都是新的,因此当前状态为”集,而不是百个包无头/定时任务模式。** 标准输入服务器仅在运行客户端附加时运行,因此有一个 CLI用于无人值守的调度:
```bash
python3 berserk.py --worker --auto-queue --max-jobs 2 --rift
```
检测新源队,然后排空最多 `--obs` 个待处理作业,然后退出 0(如果任何作业需要,则退出 1)。示例:
```
*/30 * cd /path/to/berserk-mcp && python3 berserk_mcp.py --worker --auto-queue --max-jobs 2 >> ~/.local/state/berserk-worker.log 2>&1
```
**配置**(所有配置项均为可选 - 如果未配置提供者,则跳过):
| 变量 | 默认值 | 用途 |
|---|---|---|
| `BERSERK_LLM_LADDER` | `hermes,openai,anthropic` | 生成的提供者顺序。 |
| `HERMES_API_KEY` | — | Hermes/Open WebUI 端点的 Bearer 。 |
| `BERSERK_LLM_HERMES_URL` |://localhost:3000/api/chat/completions` | Hermes 聊天完成。 分辨率顺序:此 → 本地 `llm_config → 默认值。 可以通过 `-mcp --set-hermes-url <URL>` 持久化私有而无需在存储库中硬 |
| `BERSERK_LERMES_MODEL` | 通过 `/` 自动发现 | Hermes 模型 |
| `OPENAI_API_KEY` | — | OpenAI API |
| `BERSERK_LLM_OPENAI_MODEL` | `gpt-` | OpenAI 模型。 `ANTHROPIC_API_KEY | Anthropic API |
| `BERSERK_LTHROPIC_MODEL` | `claude-opus-4-8`ropic 模型。 |
| `BERSERK_LLM_TIMEOUT` |` | 每个 LLM 调用超时单位:秒。 |
| `K_MAX_AUTOQUEUE` |` | 单次 `detect_new_sources` 传递将排队的最大新服务数量(运行保护)。 |
无新标准库的llib.request` 进行 LLM 调用,与零依赖设计相符。
> **注意 Berserk 维护人员。功能存在的原因是 Berserk 没有/保存视图的原生功能,以编程方式创建 - 因此的解析器”被模拟为服务器自己的存储中已验证的已保存查询包。 如果 Berserk 暴露了一个用于存储 KQL 函数或服务器端保存视图的网关 RPC( 解析器等效),此管道该功能,然后生成的包将成为的 Berserk 对象。 欢迎提供有关此类原生功能是否存在或计划的信息 - 请参阅 [CONTRIBUTING.md](CONTRIBUTING.md)。
---
## 实际例子
您可以粘贴到任何 MCP 感知客户端的实际提示。 每个提示都显示了自然语言提问、模型最终调用的工具以及的答案类型。 所有这些都在廉价的默认通道上运行 - 无需前沿模型。
<!-- ... (rest of the document remains the same) -->
### ChatOps: "最近一小时内有错误吗?" (SRE 通道)
```
最近一小时内有错误吗?来自哪些服务?
```
> 调用 `errors_by_service`(`since="1h ago"`)。模型回复每个服务的错误计数,或当为空时显示“未记录错误”。在SRE通道上,如果计数超过阈值,引导模型进入 `sre_error_rate` 以查看时间序列。
### 值班人员排查: "api-gateway 健康吗?" (SRE 通道)
```
api-gateway 健康吗?错误率是多少,何时最后一次看到?
```
> 调用 `sre_service_health(service="api-gateway")`。返回总事件数、错误计数、日志/指标拆分和最后看到的时间戳。 如果错误计数高,引导模型跟进 `sre_top_error_messages`。
### 安全运营中心调查: "journal-forwarder 发生了什么?" (SOC 通道)
```
重建 journal-forwarder 在过去 2 小时内发生了什么。
```
> 调用 `soc_timeline(service="journal-forwarder", since="2h ago")`。返回带有严重性、指标名称和消息片段的时间戳事件,按最新顺序排列 — 一个现成的事件叙述,无需任何 KQL 编写。
### 安全扫描: "有新的或异常的吗?" (SOC 通道)
```
在过去 30 分钟内,有什么不寻常的吗?峰值、新来源、重复错误?
```
> 调用 `soc_log_spike`、`soc_new_services` 和 `soc_repeated_errors` 一次。SOC 引导告诉模型在总结之前扫描所有三个。
### 开发工作流: "Claude Code 使用哪些工具?" (Claude 通道)
```
Claude Code 本周最常使用的工具是什么?有错误吗?
```
> 调用 `claude_tools(since="7d ago")` + `claude_errors`。仅当将 Claude Code 会话日志通过 OTLP 转发器运送到 Berserk 时有效 - 请参阅 [docs/claude-code.md](docs/claude-code.md)。
### 新来源上线
```
我刚刚将 HAProxy 日志添加到 Berserk。集成它。
```
> (使用 `SOUL.md` /系统提示配置。)代理调用 `request_discovery(service="haproxy", role_hint="sre")`。发现工作程序在夜间运行,编写并保存 `sre_haproxy_service`。第二天早上,`run_saved` 以低成本回答 HAProxy 问题,永久。
### 自主每日健康摘要(cron / 调度代理)
```
您是值班助理。使用 Berserk MCP:
1)检查过去 6 小时内每台主机的负载(host_cpu, host_memory)。
2)计算过去 24 小时内每个服务的错误数(errors_by_service)。
3)列出最吵闹的 5 个容器(top_memory)。
编写 10 行摘要,标记任何异常并停止。
```
> 具有确定性,可以在 `gpt-4.1-mini` 或本地 Qwen2.5-7B 上无人值守运行。将其连接到 cron 作业;答案简短且可解析。
---
## 需求
- Python 3.8+
- 已安装并认证的 [`bzrk`](https://docs.bzrk.dev) CLI(`bzrk -P <profile> search "..."` 有效)。承载者令牌存储在 `bzrk` 的配置中 - 此服务器从未读取或存储它。
## 安装
```bash
pip install berserk-mcp
# 或,隔离:
pipx install berserk-mcp
# 或,在不安装的情况下运行:
uvx berserk-mcp
```
从源代码:
```bash
git clone https://github.com/ssi0202/berserk-mcp
cd berserk-mcp
pip install .
```
服务器仅使用 Python 标准库 - 没有第三方运行时依赖。安装必须包括附带的本地模块(`parser_factory.py`、`secret_scan.py`、`agent_analytics.py`、`ingestion_advisor.py`)和打包的数据(`primers/`、`ingestion_catalog.json`)。使用 `pip install .` 或构建的轮 - 不要单独复制 `berserk_mcp.py`。
## 认证到 `bzrk`
berserk-mcp 不直接与 Berserk 通信 - 它封装了 `bzrk` CLI。身份验证是 `bzrk` 的工作,而不是此服务器的。**Berserk 承载者令牌仅存储在 `bzrk` 的配置中;此服务器从未读取、存储、转发或记录它。**
推荐的一次性设置:
```bash
# 1. 使用您将从 MCP 使用的配置文件登录到 Berserk。
bzrk login # 按照提示输入端点 + 令牌
# 或
bzrk -P prod login # 登录到特定的命名配置文件
# 2. 验证身份验证适用于同一配置文件,MCP 将使用。
bzrk -P local search "default | take 1" --since "1h ago"
# 3. 将 MCP 指向该配置文件(或为 `local` 留空 BZRK_PROFILE)。
export BZRK_PROFILE=local
```
**配置文件。** Berserk 使用命名配置文件(`local`、`prod`、`staging`等),您可以更改一个环境变量以指向不同的租户。`berserk-mcp` 读取 `BZRK_PROFILE` 并将其作为 `-P <profile>` 传递给每个 `bzrk` 调用。在 `claude_desktop_config.json` 中,这看起来像 `"env": {"BZRK_PROFILE": "prod"}` - 请参阅下面的 [连接到客户端](#连接到客户端)。
**非默认 `bzrk` 二进制文件。** 如果 `bzrk` 不在 `$PATH` 上(例如,Homebrew 安装或在存储库 `.venv` 中),请将 `BZRK_BIN` 设置为完整路径。`berserk-mcp` 调用 `bzrk` 时使用参数列表 - 永远不会通过 shell - 因此不需要考虑引用。
**运行时身份验证失败。** 如果 `bzrk` 返回身份验证错误(错误的令牌、过期的会话、错误的配置文件),berserk-mcp 返回常量字符串:
```text
bzrk 身份验证失败;运行 `bzrk login` 并重试
```
原始 `bzrk` 标准错误、令牌和租户标识符从未传播给调用者 - 请参阅 [安全](#安全) 以获取完整理由。
**完整的 `bzrk` 身份验证选项**(SSO、服务帐户、配置文件)超出了本 README 的范围 - 请参阅官方 Berserk CLI 文档,网址:<https://docs.bzrk.dev>。MCP 服务器只需要 `bzrk -P <profile> search "..."` 能从 MCP 将运行的相同 shell 环境成功。
## 配置
所有配置均通过环境变量 - 全部可选:
| 变量 | 默认值 | 目的 |
|---|---|---|
| `BZRK_BIN` | `bzrk` | Berserk CLI 二进制文件的路径/名称。 |
| `BZRK_PROFILE` | `local` | 要查询的 `bzrk` 配置文件。 |
| `BZRK_TIMEOUT` | `120` | 每查询超时,秒。 |
| `BERSERK_TABLE` | `default` | 要查询的 Berserk 表。 |
| `BERSERK_MCP_LEARNED_PATH` | 平台配置目录 | 保存查询的路径(Linux 上为 `~/.config/berserk-mcp/learned.json`)。 |
| `BERSERK_MCP_ROLE` | `all` | 活动角色通道:`sre`、`soc`、`claude`、`ops` 或 `all`。控制工具可见性和引导注入。 |
| `BERSERK_MCP_PRIMERS_DIR` | 邻近的 `primers/` 目录 | 包含 `<role>.md` 引导文件。 |
| `BERSERK_MCP_REDACT` | `flag` | 输出处理:`off`、`flag` 或 `redact`。 |
| `BERSERK_MCP_REDACT_ENTROPY` | 未设置 | 设置为 `true` 以启用高熵令牌检测。 |
| `BERSERK_MCP_REDACT_PII` | 未设置 | 以逗号分隔的 PII 检查:`email,ipv4,ipv6,credit_card`。 |
| `BERSERK_MCP_INGESTION_CATALOG` | 邻近目录 | 可选的替代 `ingestion_catalog.json` 的路径。 |
| `BERSERK_MCP_TOKENS_IN_ATTR` | `claude.tokens_input` | 包含输入令牌的 Claude-Code 属性(如果您的转发器发出不同的名称,请覆盖,例如 `claude.usage.input_tokens`;不匹配只会回退到基于正文长度的估计)。 |
| `BERSERK_MCP_TOKENS_OUT_ATTR` | `claude.tokens_output` | 包含输出令牌的 Claude-Code 属性(请参见上文)。 |
解析器工厂(LLM 解析器生成)有其自己的环境变量 - 请参阅上面的 [解析器工厂(LLM 生成的查询包)](#解析器工厂(LLM 生成的查询包))。
## 连接到客户端
**兼容性。** berserk-mcp 实现 MCP 协议版本 `2025-06-18` 作为 stdio 服务器(换行分隔的 JSON-RPC 2.0)。所有 47 个已注册的工具都出现在 `tools/list` 握手并可以通过 `tools/call` 调用。该 stdio 握手路径 - 包括所有必需的生命周期方法(`initialize`、`notifications/initialized`、`ping`、`tools/list`、`tools/call`)- 已被两个独立的扫描器(Cisco AI Defense `mcp-scanner` 和 MCP-Shield)外部锻炼过,它们都通过协议错误枚举了完整的工具表面。每个方法在测试套件中都有对抗性回归覆盖;请参阅 `docs/cisco-mcp-scanner-result-report-2026-07-19.md` 获取扫描器验证。任何使用相同协议版本的客户端 - Claude Desktop、Claude Code 和第三方 MCP 客户端 - 都可以在无需服务器端更改的情况下驱动它。
### Claude Desktop
将以下内容添加到 `claude_desktop_config.json`(设置 → 开发者 → 编辑配置):
```json
{
"mcpServers": {
"berserk-q": {
"command": "berserk-mcp",
"env": {
"BZRK_PROFILE": "local",
"BERSERK_MCP_ROLE": "sre"
}
}
}
}
```
如果您没有 `pip install`,请指向文件:
```json
{
"mcpServers": {
"berserk-q": {
"command": "python",
"args": ["/absolute/path/to/berserk_mcp.py"],
"env": {
"BZRK_PROFILE": "local",
"BERSERK_MCP_ROLE": "sre"
}
}
}
}
```
### Claude Code
```bash
claude mcp add berserk-q -- berserk-mcp
# 或从源代码:
claude mcp add berserk-q -- python /absolute/path/to/berserk_mcp.py
```
在 shell 或 `.env` 中设置角色:
```bash
BERSERK_MCP_ROLE=sre claude mcp add berserk-q -- berserk-mcp
```
### 任意 MCP 客户端
以 stdio MCP 服务器的身份启动 `berserk-mcp`(或 `python berserk_mcp.py`)。它通过 stdio 以换行分隔的 JSON-RPC 2.0 协议版本 2025-06-18 进行通信。
## 选择模型
固定查询设计的全部目的是 **模型从不编写 KQL** - 它只选择工具和时间窗口。这将能力门槛从“可以编写正确的 Kusto”降低到“可以进行基本的工具调用”,这就是为什么廉价且本地的模型是可行的。优先使用最便宜且有效的模型:
- **本地(首选)。** 任何具有可靠工具调用的 Ollama/LM-Studio 模型:**Qwen2.5-Instruct** 家族(7B 是最佳选择)、**Llama 3.1/3.3** 或 **Mistral-Small**。微型模型(≤2B)和仅 CPU 预填充的模型难以进行代理工具调用循环 - 优先使用 GPU 和 ≥7B 进行无人值守使用。
- **廉价 API。** `gpt-4.1-mini`、Claude **Haiku** 或 Gemini **Flash** - 以一小部分的前沿成本提供强大的工具使用。适用于延迟敏感的 ChatOps 回复。
- **前沿模型** 通常不是必要的;为依赖 `search` 和 `save_query` 的开放式调查保存它们。
最大可靠性杠杆:工具 **描述**。它们被编写得很窄且无歧义,以便小型模型正确路由 - 如果您添加工具,请保持它们的这种特性。
## 安全
- **注入防护。** `logs_for_service` 和 `sre_service_health`/`soc_timeline` 验证服务名称是否符合 `[A-Za-z0-9._-]`。`claude_search` 拒绝引号、管道、反斜杠和反引号。两者都插入到 KQL 字符串字面量中,因此阻止了单引号注入。所有其他工具都使用完全固定的查询,无插值。
- **仅读构造。** 每个工具都被注释(`readOnlyHint`),并且只发出读 KQL。唯一的例外是 `save_query`(写入本地查询文件,永不写入 Berserk)和 `request_discovery`(写入本地队列文件)。
- **无 shell。** `subprocess` 始终使用参数列表(而非 `shell=True`)调用;无 `eval`。
- **此代码中无机密。** Berserk 承载者令牌仅存储在 `bzrk` 的配置中。该服务器从未读取、存储或记录它。
- **失败关闭的机密扫描。** `scan_secrets` 拒绝在任何解析失败或多表响应上报告“干净”;响应要么完全解码并验证每个审计记录,要么返回受控的 `机密扫描失败` 错误,无内容回声。
- **仅向 LLM 提供结构化遥测。** 生成管道投射 `bag_keys(...)`、`has_body`、`has_metric` 和长度限制、完全编辑的摘录 - 原始遥测值从未发送到任何提供者。
- **有界的编辑。** `redact()` 使用显式 `MAX_REDACT_CHARS = 1_000_000` 和 `MAX_REDACT_CANDIDATES = 50_000` 限制,以及一个排序-合并-连接管道,如果边界违规,则失败关闭到 `[REDACTED:redaction_limit]` - 永远不会返回部分原始文本。
- **恒定的身份验证失败消息。** `bzrk` 身份验证失败始终返回常量字符串 `"bzrk 身份验证失败;运行 \`bzrk login\` 并重试"` - 永远不会是原始标准错误、令牌或租户标识符。
- **JSON-RPC 2.0 严格的信封验证。** `initialize` 需要一个非空字符串 `protocolVersion` 和对象类型的 `capabilities`/`clientInfo`;`ping` 和 `tools/list` 拒绝非空参数;作为请求的通知被拒绝,错误代码为 `-32600`;意外的处理程序异常表现为 `-32603` 而不是静默转换为 `isError=true` 结果。
- **生成的查询策略。** LLM 生成的查询必须以 `{table} | ...` 开头,必须以 `| take N` 结尾,其中 `1 ≤ N ≤ 50`,并且必须在 2,000 个字符内。策略检查应用于 KQL 的剥离副本,其中移除了字符串字面量和 `//` 注释,因此操作员文本在引用的字符串或注释中无法满足检查。
- **提供者错误净化。** 来自 LLM 提供者的 HTTP 错误仅返回 `"HTTP <code>"` - 响应正文和异常消息从未传播给调用者。
- **LLM 端点方案允许列表。** 操作员配置的 LLM 端点 URL(通过 `--set-hermes-url` 或 `BERSERK_LLM_HERMES_URL`)在写入和调用时都会验证:仅接受 `http://` 和 `https://` 方案;控制字符和换行注入变体在任何 `urllib.request.urlopen` 调用之前被拒绝。防御深度对抗 `file://`、`gopher://`、`ftp://` 和请求走私尝试,即使操作员在信任边界内。
- **存储路径验证。** 从操作员环境变量读取的文件系统路径(`BERSERK_MCP_LEARNED_PATH`、`XDG_CONFIG_HOME`、`APPDATA`)在使用前会验证:必须是绝对路径,不能包含 `..` 段,不能通过 `..` 解析,不能包含控制字符。相同的验证器在每个 I/O 接收器上运行(`load_json_list`、`save_json_list`、`load_learned`、`save_learned`、`_ensure_private_dir`、`load_json_dict`、`save_json_dict`),以便任何未来的调用者 - 而不仅仅是操作员环境变量路径 - 都受到保护。
**输出注意。** 工具结果是您的遥测中包含的内容。如果 Berserk 中的日志包含敏感值,`logs_for_service`/`search` 可以使它们浮出水面 - 在入口处编辑,而不是在这里。
### 安全审查和测试
安全相关接口已经过多轮审计和外部扫描:
- **人工审计** 涵盖 15 个发现(7 个阻止安全/DR,加上 8 个延迟的行为/文档问题),每个问题都有对抗性回归测试。
发现和关闭证据: [`docs/security-bug-review-report-2026-07-18.md`](docs/security-bug-review-report-2026-07-18.md)。
- **差异化再评审** 产生了 6 个额外发现(`FVR-001` 至 `FVR-006`),全部已关闭:
[`docs/security-fix-validation-report-2026-07-19.md`](docs/security-fix-validation-report-2026-07-19.md)。
- **外部扫描器通过** - Cisco AI Defense `mcp-scanner`(YARA stdio + pip-audit)、MCP-Shield(线级工具描述关键词扫描)和 Snyk Code(GitHub 源代码的 SAST):0 个真实发现。
MCP-Shield 产生了 3 个关键词误报(文档记录)。Snyk 产生了两个操作员控制的输入污染发现(CWE-918 SSRF 和 CWE-23 路径遍历)- 两个都是威胁模型中的假阳性,通过防御深度方案/路径允许列表解决。完整分析:
[`docs/cisco-mcp-scanner-result-report-2026-07-19.md`](docs/cisco-mcp-scanner-result-report-2026-07-19.md)。
- **持续验证:** 测试套件(`tests/`,276 个测试 + 2 个角色测试)包括上述每个发现的对抗性回归,并会在每次发布前运行。参见 `## 测试`。
## 测试
```bash
python -m pytest tests/ -q
# 支持标准库 unittest:
python3 -m unittest discover -s tests
```
测试模拟了 `bzrk` CLI,因此它们验证了:KQL 内容和锁定字符串、默认时间窗口、角色隔离(哪些工具出现在哪个通道)、注入防护、`since` 验证、工具注释、JSON-RPC 协议、学习循环、发现队列重复和修订日志行为。解析器套件还伪造了 LLM HTTP 层,以验证升级梯度、源配置文件、新源/漂移检测、生成 + 验证 + 细化以及无头工作器模式。分析套件验证了循环检测、模型拟合分类、MCP 调度以及无头 `--agent-report` 路径。
现场验证,而非仅仅是单元测试
存根套件证明了服务器的逻辑在内部是一致的;但它无法证明KQL实际上能正确地在真正的集群上执行。单独地,每个SRE和都通过服务器的实际调度路径,在实时Berserk部署中运行——而这一过程发现了两个单元测试无法发现的真正错误:
- `soc_new_services`的天窗口没有分片字段,因此它扫描了未索引的数据,并在实际数据超时。缩小到`24小时前`;确认在约28秒内返回完整结果。
- `sre_host_headroom`返回原始字节作为内存,而不是转换为GB(与已经这样做的`host_memory`不同)——由模型总结为“16.1亿字节”。已修复:内存现在以GB为单位报告,显式`unit`列将其负载平均行区分开来。
`trace_*`工具(v1.0)经过了,并发现了另外两个真正的错误——一个动态类型`按`排序和一个错误的排序键,导致子节点在父节点之前进行跨度排序。有关完整的编写过程,请参见上面的[跟踪工具](#trace-tools-all-lanes),包括在编写这些工具时阻止验证的中断。
`claude_token_burn`/`claude_loop_check`/`claude_model_fit`三件套(v1.14.1)引发了一个更大的问题:JSON形状不匹配意味着这三个工具在针对实际Berserk输出时都默默地返回了零结果,没有错误——有关完整的编写过程,请参见上面的[代理日志智能](#agent-log-intelligence)。
所有修复都已在当前版本中。
## 扩展 - 五分钟内添加新工具
这个服务器的重点是固定且经过验证的查询——因此添加工具是一个小型机械仪式。目标是保持路由表面较小(约20个核心工具),并通过学习循环让长尾在`save_query`/`run_saved`后面累积。
**1.实例上找到KQL。** 使用`bzrk`迭代,直到查询返回干净的行——名称、单位、排序顺序。*不要部署一个您尚未看到在实际数据上成功的查询。*
```bash
bzrk -P local search "default | where metric_name == 'system.network.io' \
| summarize bytes=sum(value) by host=tostring(resource['host.name'])" \
--since "1小时前"
```
**2. 添加工具条目:**
```python
TOOLS.append({
"name": "host_network",
"roles": ["sre"], # 省略以使其对所有通道可见
"description": "每个主机总网络字节数(总和)。按主机;如果要按容器,请现在使用`search`。",
"inputSchema": {"type": "object", "properties": _since()},
})
TITLES["host_network"] = "每主机网络I/O"
```
将其连接到调度器(固定的`cmd`键为测试添加KQL常量。
**3. 使用测试锁定查询**
```python
def test_net_locked(self):
self.assertIn("system.network.io", bm.Q_HOST_NET)
```
**4.件 + 重新注册:**
```bash
python -m pytest tests/ -q
claude mcp remove berserk-q && claude mcp add berserk-q -- berserk-mcp
```
需要触及自由文本输入(服务名称)的工具需要一个允许列表(请参见`logs_for_service`)。需要两个`bzrk`往返的工具可以遵循`discover的模式。两者都在源代码中作为模板。
## 贡献
问题、想法和PR都欢迎——有关简要版本,请参见[CONTRIBUTING.md](CONTRIBUTING.md)。门槛很低:如果测试通过,描述很窄,并且查询已在实际数据上运行过,那么就可以合并。
良好的首次贡献:
- 一个新的固定查询工具,用于获取您关心的遥测数据
- [docs/](docs/)下您所在堆栈(Kubernetes、ECS、Nomad等)的示例
- 改进您模型的工具描述,该描述不清楚——描述是路由器;更清晰的描述是真正的正确性改进
- 当您遇到服务器应该具有工具的功能时,请提交问题
## 许可证
[MIT](LICENSE)。
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器