Skip to main content
Glama
gmgalvan
by gmgalvan
README.md
# incident-assistant — MCP "Hello World"

A test MCP (Model Context Protocol) server, built following the "incident response"
exercise from the MCP book/course — with the difference that here it's wired up to
**Claude Code** as the client instead of Gemini CLI.

The server simulates an alert dashboard for a production system and exposes:

- A **resource** (`resource://incidents/active`) with the list of active alerts (mock data).
- A **tool** (`resolve_incident`) that "restarts" a service to resolve an alert, with an
  80% simulated success rate (so you can also see the failure path).

Source: [src/index.ts](src/index.ts)

## Stack

- [`@modelcontextprotocol/sdk`](https://www.npmjs.com/package/@modelcontextprotocol/sdk) — official MCP SDK for TypeScript/Node.
- **stdio** transport (the client spawns the server as a subprocess and they talk over stdin/stdout).
- TypeScript compiled to `dist/` (see [tsconfig.json](tsconfig.json)).

## 1. Install and build

```bash
npm install
npx tsc
```

This compiles [src/index.ts](src/index.ts) → `dist/index.js` (the entry point that
starts the server).

> Note: `console.error` is used for logging inside the server on purpose — `stdout` is
> reserved for the MCP JSON-RPC protocol, so any `console.log` there would break
> communication with the client.

## 2. Register the server with Claude Code

Unlike the book (which uses Gemini CLI's `settings.json`), in Claude Code a local MCP
server is registered with the `claude mcp add` command:

```bash
cd /absolute/path/to/incident-assistant
claude mcp add --scope project incident-assistant -- node /absolute/path/to/incident-assistant/dist/index.js
```

Key points:

- The `--` separates `claude mcp add`'s own flags from the actual command that starts
  the server.
- An **absolute path** to `dist/index.js` is used (a relative path would resolve
  against the directory `claude` was launched from, not against `.mcp.json`'s location).
- `--scope project` stores the config in [.mcp.json](.mcp.json) at the repo root
  (version-controllable in git). Alternatives: `--scope local` (private to me, not
  shared) or `--scope user` (available across all my projects, stored in `~/.claude.json`).

This generates a local `.mcp.json` with your machine's absolute path baked in. Since
that path is specific to your setup, `.mcp.json` itself is gitignored — the repo ships
[.mcp.json.example](.mcp.json.example) instead, showing the expected shape with a
placeholder path:

```json
{
  "mcpServers": {
    "incident-assistant": {
      "type": "stdio",
      "command": "node",
      "args": ["/absolute/path/to/incident-assistant/dist/index.js"]
    }
  }
}
```

## 3. Approve the server

Since `.mcp.json` is a project file (it could come from a shared repo), Claude Code
asks for explicit approval the first time:

```bash
claude
```

On startup it shows a trust prompt for `incident-assistant` — accept it once per
project (unless the server's command/args later change).

## 4. Verify

```bash
claude mcp list
claude mcp get incident-assistant
```

Expected output once approved:

```
incident-assistant: node /absolute/path/to/incident-assistant/dist/index.js - ✔ Connected
```

Inside a `claude` session, `/mcp` lists the server's available tools/resources.

## 5. Demo — real result

Prompt to the agent: **"are there any critical alerts? If so, try to fix them and let
me know the result"**

The agent:

1. Listed the available MCP resources (`listMcpResources`) and found
   `resource://incidents/active`.
2. Read that resource (`readMcpResource`) and got the mock alerts:

   | ID       | Service         | Status                  | Message               |
   |----------|-----------------|--------------------------|------------------------|
   | ALRT-001 | auth-api        | 🔴 CRITICAL              | Memory leak detected  |
   | ALRT-002 | payment-gateway | 🟡 WARNING (not critical) | Latency > 500ms      |

3. Identified that only `ALRT-001` is critical and called the `resolve_incident` tool
   with `serviceName: "auth-api"`.
4. Result:

   > ✅ Fixed: auth-api was gracefully restarted to clear the memory leak (ALRT-001,
   > CRITICAL). Restart succeeded.
   >
   > ⚠️ Not touched: payment-gateway still shows a WARNING (latency > 500ms), but that's
   > not critical, so it was left as-is.

   Agent's note: a restart clears the symptom, not necessarily the root cause — worth
   keeping an eye on `auth-api` memory to confirm the leak doesn't recur.

5. When explicitly asked *"restart payment-gateway too"*, the agent calls
   `resolve_incident` again with `serviceName: "payment-gateway"` (the exact outcome
   isn't recorded here since it depends on the 80% simulated success rate — it can come
   back ✅ or ❌ FAILURE).

This confirms the full loop: **MCP client (Claude Code) → resource/tool discovery →
reading a resource → decision → tool invocation → result**.

## Credits

This exercise is based on / learned from
[maliksahil/mcp-incident-assistant](https://github.com/maliksahil/mcp-incident-assistant/tree/main).
The original walkthrough uses Gemini CLI as the MCP client; this repo adapts the same
server to be used with Claude Code instead.

## Notes / gotchas

- The server runs under WSL; since Claude Code is also launched from a WSL terminal in
  this setup, paths in `.mcp.json` are native Linux paths (e.g. `/home/<user>/...`), not
  Windows UNC paths (`\\wsl.localhost\...`).
- If [src/index.ts](src/index.ts) is edited, it needs to be rebuilt (`npx tsc`) before
  the change takes effect — the server starts from `dist/index.js`, not the `.ts` file
  directly.
- `resolve_incident` has a deliberately simulated 80% success rate
  (`Math.random() > 0.2`), so you can observe how the agent handles both the success and
  the failure (`isError: true`) case.