Skip to main content
Glama
alonf

Linux Diagnostics MCP Server

by alonf
README.md
# Linux Diagnostics MCP Server - Lecture Demo

A Python/Linux adaptation of the original `MCPDemo` teaching repository. This repo now reaches **Milestone 7 parity** for the public teaching flow: compact system inspection, Linux process drill-down, log snapshots as resources, workflow prompts, authenticated MCP over HTTP on `/mcp`, explicit elicitation before process termination, sampling-assisted Linux diagnostics, and allowed-root proc/sys snapshots.

## What This Demo Shows

This lecture demo now includes:
- ✅ **Tools**: Linux diagnostics tools for `get_system_info`, `get_process_list`, `get_process_by_id`, `get_process_by_name`, and elicitation-gated `kill_process`
- ✅ **Resources**: paged `syslog://snapshot/...` log snapshot resources
- ✅ **Prompts**: MCP workflow prompts for error analysis, CPU investigation, security review, and health diagnosis
- ✅ **HTTP transport**: streamable MCP over `http://127.0.0.1:5000/mcp`
- ✅ **API key auth**: `X-API-Key` header or `?apiKey=secure-mcp-key`
- ✅ **AI Chat Client**: a Python Azure OpenAI client that launches the local HTTP server, lets the model call MCP tools, prompts, and resources, and handles local form elicitation in the terminal
- ✅ **Python 3.12 implementation** with the official MCP Python SDK
- ✅ **Multiple testing methods**
- ✅ **Milestone 5 elicitation** for `kill_process`
- ✅ **Milestone 6 sampling-assisted Linux diagnostics**
- ✅ **Milestone 7 roots** for read-only `/proc` and `/sys` snapshots

## Quick Start

### 1. Install

Server-only install:

```bash
python3 -m pip install --user --break-system-packages -e .
```

Install the lecture chat client extras:

```bash
python3 -m pip install --user --break-system-packages -e '.[llm]'
```

### 2. Quick Smoke Test (No LLM)

```bash
python3 scripts/smoke_test.py
```

This script:
1. Starts the local HTTP MCP server
2. Verifies `401 Unauthorized` without an API key
3. Performs the MCP initialize handshake on `/mcp`
4. Confirms `mcp-session-id` flow works across requests
5. Discovers tools, prompts, and resource templates
6. Exercises the system, process, log snapshot, proc snapshot, and sampling-assisted diagnostics flows
7. Verifies `kill_process` fails safely when the client does not advertise elicitation support
8. Verifies the lecture chat client fails safely when Azure OpenAI settings are missing

### 3. Run the Server Manually

```bash
python3 -m mcp_linux_diag_server
```

The server listens on:

- endpoint: `http://127.0.0.1:5000/mcp`
- demo API key: `secure-mcp-key`

### 4. Test with MCP Inspector or VS Code MCP config

Start the server in one terminal, then connect using the HTTP endpoint above.

This repo includes `.vscode/mcp.json` with the required header:

```json
{
  "servers": {
    "linux-diag-demo": {
      "url": "http://127.0.0.1:5000/mcp",
      "headers": {
        "X-API-Key": "secure-mcp-key"
      }
    }
  }
}
```

If your inspector accepts a URL directly, this query-string form also works:

```text
http://127.0.0.1:5000/mcp?apiKey=secure-mcp-key
```

### 5. Use the Lecture Chat Client

Copy the sample environment file and fill in your local Azure OpenAI settings:

```bash
cp .env.example .env.local
$EDITOR .env.local
python3 -m mcp_linux_diag_server.client --prompt "Summarize this machine."
```

To mirror the original .NET credential flow more closely, set:

```bash
MCP_DEMO_AZURE_OPENAI_USE_DEFAULT_CREDENTIAL=true
```

and omit the API key.

Run interactive chat:

```bash
python3 -m mcp_linux_diag_server.client
```

Or run a single prompt:

```bash
python3 -m mcp_linux_diag_server.client --prompt "What is the system information?"
```

## The Tools

### System Information
- **`get_system_info`** - Returns a compact Linux or WSL system snapshot
  - Host name
  - Current user
  - Linux distribution description
  - Kernel release
  - Architecture
  - Logical CPU count
  - Python runtime
  - Current working directory
  - Uptime
  - Load averages
  - Memory summary
  - WSL detection flag

### Process Inspection
- **`get_process_list`** - Returns a lightweight list of running processes with names and PIDs
- **`get_process_by_id`** - Returns detailed Linux process information for one PID
- **`get_process_by_name`** - Returns paged detailed process information for a process name
  - Defaults to `page_number=1`
  - Defaults to `page_size=5`
  - Keeps the list-first, detail-second teaching flow from the original demo
- **`kill_process`** - Terminates a Linux process only after explicit elicitation
  - If `process_id` is omitted, the server samples the top CPU consumers and asks the client to choose one
  - The server always requires the typed confirmation phrase `CONFIRM PID {pid}`
  - The lecture client handles these prompts locally in the terminal when stdin/stdout are interactive
- **`troubleshoot_linux_diagnostics`** - Uses sampling to convert a natural-language Linux diagnostics question into a validated `/proc` or `/sys` read
  - The server validates the sampled path and field against an allowlist before reading anything
  - Exact Python adaptation: the sampled query is a single safe `PATH` or `PATH | grep FIELD` line instead of WQL
  - The server then samples again to summarize the observation back to the user
- **`create_proc_snapshot`** - Creates an immutable read-only snapshot from an allowed `/proc` or `/sys` path and returns resource URIs
  - File snapshots page line-by-line content
  - Directory snapshots page deterministic child metadata without following symlinks
  - Enforces explicit allowed roots before reading anything
- **`request_proc_access`** - Uses elicitation to request read-only access to an additional `/proc` or `/sys` root
  - Adds the approved root to the server's in-memory allowlist
  - Lets the model ask for access proactively before a blocked snapshot attempt

### Log Snapshots
- **`create_log_snapshot`** - Creates an immutable snapshot from a common Linux log file and returns resource URIs
  - Supports `system`, `security`, `kernel`, and `package` log groups
  - Optional `filter_text` narrows the snapshot to matching lines
  - Returns a base resource URI plus a paginated resource template

## Resources

- **`syslog://snapshot/{snapshot_id}`** - Reads a stored Linux log snapshot with default pagination
- **`syslog://snapshot/{snapshot_id}?limit={limit}&offset={offset}`** - Reads a specific page from a stored snapshot
- **`proc://snapshot/{snapshot_id}`** - Reads a stored proc/sys snapshot with default pagination
- **`proc://snapshot/{snapshot_id}?limit={limit}&offset={offset}`** - Reads a specific page from a stored proc/sys snapshot

Every resource read returns:
- snapshot metadata
- captured entries
- pagination metadata (`total_count`, `returned_count`, `limit`, `offset`, `has_more`, `next_offset`)

## Prompts

- **`AnalyzeRecentApplicationErrors`** - Error-focused log analysis workflow
- **`ExplainHighCpu`** - Correlate CPU-heavy processes with Linux logs
- **`DetectSecurityAnomalies`** - Review suspicious processes plus auth/security log evidence
- **`DiagnoseSystemHealth`** - End-to-end system health workflow
- **`TroubleshootLinuxComponent`** - Focused deep-dive workflow that steers the agent toward `troubleshoot_linux_diagnostics`

## Projects

### `src/mcp_linux_diag_server/server.py`
The authenticated HTTP MCP server exposing the Milestone 1-7 diagnostics tools, resources, and workflow prompts.

### `src/mcp_linux_diag_server/client.py`
The lecture chat client that:
- launches the local HTTP server
- connects over streamable HTTP with the demo API key
- exposes MCP prompt/resource APIs as helper tools for the model
- fulfills MCP form elicitation in the local terminal when the model triggers `kill_process`
- fulfills MCP sampling requests so the server can synthesize safe Linux diagnostics queries and summaries
- teaches the model to request proc/sys access before snapshotting blocked paths
- executes tool-calling turns

## Testing Methods

| Method | Visual | Interactive | LLM | Best For |
|--------|--------|-------------|-----|----------|
| `python3 scripts/smoke_test.py` | ❌ No | ❌ No | ❌ No | quick verification of M1-M7 server behavior |
| MCP Inspector / `.vscode/mcp.json` | ✅ Yes | ✅ Yes | ❌ No | development, debugging, teaching |
| `python3 -m mcp_linux_diag_server.client` | ❌ No | ✅ Yes | ✅ Yes | lecture demo flow |

For the Milestone 1 validation checklist that still underpins the base lecture flow, see [M1_VALIDATION_GUIDE.md](M1_VALIDATION_GUIDE.md).

## Project Structure

```text
MCPPythonDemo/
├── README.md
├── LICENSE.txt
├── pyproject.toml
├── .env.example
├── .vscode/
│   └── mcp.json
├── scripts/
│   └── smoke_test.py
├── src/
│   └── mcp_linux_diag_server/
│       ├── __main__.py
│       ├── client.py
│       ├── http_config.py
│       ├── server.py
│       └── tools/
│           ├── log_snapshots.py
│           ├── proc_snapshots.py
│           ├── processes.py
│           └── system_info.py
├── tests/
│   ├── http_harness.py
│   ├── test_client.py
│   ├── test_m1_smoke.py
│   ├── test_m2_smoke.py
│   ├── test_m3_smoke.py
│   ├── test_m4_http.py
│   ├── test_log_snapshots.py
│   ├── test_processes.py
│   └── test_system_info.py
```

## Requirements

- Python 3.12+
- `mcp[cli]`
- Azure OpenAI only if you want to run the lecture chat client

## Milestones

✅ **Milestone 1** - Minimal diagnostics tool over stdio plus lecture chat client  
✅ **Milestone 2** - Process inspection  
✅ **Milestone 3** - Log snapshot resources and prompts  
✅ **Milestone 4** - HTTP transport and security  
✅ **Milestone 5** - Elicitation-backed `kill_process`  
✅ **Milestone 6** - Sampling-assisted Linux diagnostics  
✅ **Milestone 7** - Roots and proc/sys snapshots

## License

MIT. See [LICENSE.txt](LICENSE.txt).

## Resources

- [Model Context Protocol](https://modelcontextprotocol.io/)
- [MCP Inspector](https://github.com/modelcontextprotocol/inspector)
- [Azure OpenAI](https://azure.microsoft.com/en-us/products/ai-services/openai-service)
- [Original C# MCPDemo](https://github.com/alonf/MCPDemo)