incident-tool

incident-tool

Enables AI agents to diagnose Linux server incidents by collecting and structuring system diagnostics from multiple servers via SSH, with tools for finding incident clusters, gathering context (memory, CPU, swap, etc.), and running arbitrary commands.

Category
访问服务器

README

mcp-incident-tool

An MCP server for Linux incident diagnosis. Gives AI coding agents structured access to multi-server diagnostics without flooding the context window with raw logs.

The Problem

AI agents are good at root-cause analysis, but they need the right data first. Diagnosing a crash typically means SSHing into multiple machines, scraping journalctl, sar, ipmitool, and last, then figuring out which boot contained the failure. Raw journalctl output for one boot can exceed 100,000 lines — dumping that into a chat context buries the signal and exhausts the token budget before any real analysis happens.

This tool collects, filters, and structures that data so the agent can reason over it efficiently.

Tools

find_incidents

Scans recent boot cycles and clusters error events by time proximity (a 10-minute gap) into discrete incidents. If a boot cycle has multiple bursts of errors separated in time, it will produce multiple incidents sharing the same boot_idx.

[
  {
    "boot_idx": 0,
    "start_time": "2026-03-24T11:45:00.000000+08:00",
    "end_time": "2026-03-24T11:58:44.000000+08:00",
    "event_count": 2,
    "has_shutdown": true,
    "shutdown_type": "hard_lockup",
    "events": [
      { "time": "2026-03-24T11:45:00.000000+08:00", "unit": "kernel",
        "message": "Out of memory: Killed process 8821 (java) total-vm:48329416kB" },
      { "time": "2026-03-24T11:58:44.000000+08:00", "unit": "systemd",
        "message": "Boot ended: hard_lockup" }
    ]
  },
  {
    "boot_idx": 0,
    "start_time": "2026-03-24T11:20:00.000000+08:00",
    "end_time": "2026-03-24T11:20:00.000000+08:00",
    "event_count": 1,
    "has_shutdown": false,
    "shutdown_type": null,
    "events": [
      { "time": "2026-03-24T11:20:00.000000+08:00", "unit": "kernel",
        "message": "Out of memory: Killed process 1234 (python) total-vm:16384000kB" }
    ]
  },
  {
    "boot_idx": -1,
    "start_time": "2026-03-23T08:00:00.000000+08:00",
    "end_time": "2026-03-23T08:00:00.000000+08:00",
    "event_count": 1,
    "has_shutdown": true,
    "shutdown_type": "clean_reboot",
    "events": [
      { "time": "2026-03-23T08:00:00.000000+08:00", "unit": "systemd",
        "message": "Boot ended: clean_reboot" }
    ]
  }
]

The agent sees: boot 0 had two distinct OOM cases, followed by a hard lockup. Boot -1 was a clean reboot. It calls get_context with an incident's end_time to pull the full picture.

get_context

Takes a timestamp and fires 9 SSH calls in parallel across both servers, returning a single structured payload for the window [end_time - duration, end_time]. The typical usage is passing an incident's end_time from find_incidents, but any point in time works.

Source What it answers
journalctl (primary server) What services failed and when
sar -r memory Was RAM exhausted? Was virtual overcommit high?
sar -u CPU Was %iowait spiking? Was the kernel saturated?
sar -W swap Was the kernel paging before OOM fired?
sar -q load How many processes were blocked on I/O?
ipmitool sel Any hardware events? Rules out hardware failure.
last -F sessions Who was logged in when the machine died?
journalctl (auth server) Was NFS or NIS a factor?
uptime + service status (auth server) Is the NIS/NFS stack healthy?
{
  "window":  { "start": "2026-03-24T11:28:00.000000+08:00", "end": "2026-03-24T11:58:00.000000+08:00" },
  "memory":  { "peak_pct": 94.7, "peak_commit_pct": 98.2, "peak_time": "2026-03-24T11:40:00+08:00", "samples": [...] },
  "cpu":     { "peak_busy_pct": 83.2, "peak_iowait_pct": 76.4, "samples": [...] },
  "swap":    { "any_activity": false, "samples": [...] },
  "load":    { "peak_blocked": 47, "samples": [...] },
  "ipmi":    { "events": [] },
  "journal": { "events": [] },
  "sessions": ["abat", "kyle0"],
  "abc":     { "ypserv": "active", "nfs": "active", "load": "0.12, 0.08, 0.05", "errors": [] }
}

From this: RAM hit 94%, virtual commit at 98%, iowait spiked to 76% with 47 blocked processes, hardware was clean, NFS was up. The OOM triggered a task queue seizure that locked the machine.

run_command

Runs an arbitrary shell command on either server as the unprivileged user. No sudo. Used for targeted follow-up when the agent wants to chase a lead.

run_command("a6k", "getent passwd 1031")   # who owns a UID from the OOM log?
run_command("a6k", "ls -lh /var/crash/")  # any kernel crash dumps?
run_command("a6k", "nvidia-smi")           # GPU driver state

Prerequisites

  • Python 3.12+
  • SSH key access to the target machines
  • sysstat collecting data on the primary server
  • NOPASSWD sudoers on the primary server for journalctl and ipmitool:
echo 'your_user ALL=(root) NOPASSWD: /usr/bin/journalctl, /usr/bin/ipmitool' \
  | sudo tee /etc/sudoers.d/mcp-incident

Installation

git clone <repo-url> mcp-incident-tool
cd mcp-incident-tool
python -m venv .venv
source .venv/bin/activate
pip install -e .

Configuration

cp .env.example .env
A6K_HOST=<primary server IP>
A6K_USER=<username>
A6K_SSH_KEY=~/.ssh/id_ed25519

ABC_HOST=<auth server IP>
ABC_PORT=22
ABC_USER=<username>
ABC_SSH_KEY=~/.ssh/id_ed25519

The server exits immediately on startup if any required variable is missing.

Connecting to Claude Code

Add to ~/.claude.json under mcpServers:

{
  "mcpServers": {
    "incident-tool": {
      "type": "stdio",
      "command": "/absolute/path/to/.venv/bin/python",
      "args": ["/absolute/path/to/server.py"]
    }
  }
}

Use absolute paths. Claude Code spawns the server on startup and communicates over stdin/stdout JSON-RPC.

Project Structure

mcp-incident-tool/
  server.py            MCP entry point, tool registration
  core/
    config.py          Environment loading, fails fast on missing vars
    ssh_client.py      SSHClient and SSHManager (asyncssh, persistent connections)
  tools/
    find_incidents.py  Boot scanning, event clustering, shutdown detection
    get_context.py     Parallel context aggregation orchestrator
    run_command.py     Ad-hoc command execution
  parsers/
    journal.py         journalctl JSON parser, priority and keyword filtering
    sar.py             sysstat/sar parser for memory, CPU, swap, and load
    ipmi.py            ipmitool SEL hardware event log parser
    last.py            wtmp session record parser with crash detection
  tests/
    test_find_incidents.py   Offline unit tests (pytest, no SSH required)
    test_tools.py            Integration CLI, mirrors Claude's MCP call signature
    test_*.py                Per-source integration smoke tests

Running Tests

Offline unit tests:

source .venv/bin/activate
pytest tests/test_find_incidents.py

Integration CLI:

python tests/test_tools.py find_incidents --start-from 0 --num-boots 5
python tests/test_tools.py get_context --end-time "2026-03-24T14:00:00+08:00"
python tests/test_tools.py run_command a6k "uptime"

See tests/README.md for the full breakdown of offline vs. live test categories.

Typical Workflow

A full investigation from prompt to root cause takes three tool calls.

User: "Why did the server crash yesterday afternoon?"

1. find_incidents(start_from=0, num_boots=10)
   → boot -3, hard_lockup, 2026-03-24T11:58:44+08:00

2. get_context(end_time="2026-03-24T11:58:44+08:00", duration_minutes=30)
   → memory peaked at 94.7%, iowait at 76.4%, 47 processes blocked on I/O,
     OOM killed process 8821, hung_task followed 2 minutes later,
     hardware clean, NFS healthy

3. run_command("a6k", "getent passwd 1031")
   → resolves the UID from the OOM log to identify which user's workload
     triggered the cascade

Agent conclusion: a memory-heavy job exhausted RAM, the kernel OOM-killed it,
and the resulting I/O stall locked the machine. Hardware and NFS ruled out.

No manual SSH. No copy-pasting logs. The agent drives the investigation end to end.

Design Notes

Structured output over raw logs. Raw journalctl output for one boot can be 100,000+ lines. The parsers extract only error-level and keyword-matched events. The agent works with 5 to 20 structured records, not raw text.

Parallel SSH for get_context. The 9 data sources are independent. With asyncio.gather and a semaphore to respect OpenSSH's MaxSessions limit, all calls complete in the time of the slowest one, typically under 5 seconds.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选