Skip to main content
Glama
README.md
# snmp-mcp

Local **stdio MCP server** for **SNMPv2c** read-only queries. Community strings come from a CIDR config file; agents call low-level `snmp_get` / `snmp_walk` with numeric or MIB-qualified OIDs.

Product requirements: [PRD.md](PRD.md).

---

## Requirements (every machine)

| Need | Notes |
|------|--------|
| **Python 3.11+** | For install via `pipx` / `uv` / `pip` |
| **net-snmp CLI** | Optional on `feature/pysnmp`: only needed for `--backend netsnmp` |

```bash
**Default backend (`feature/pysnmp` branch): pure-Python [pysnmp](https://pypi.org/project/pysnmp/).**  
No net-snmp install required for basic get/walk.

Optional fallback to CLI:

```bash
# macOS (Homebrew) — only if using --backend netsnmp
brew install net-snmp
```

```bash
snmp-mcp --backend pysnmp ...    # default
snmp-mcp --backend netsnmp ...   # requires snmpget/snmpwalk on PATH
# or: SNMP_MCP_BACKEND=netsnmp
```

---

## Install (easy, another machine)

Goal: a global `snmp-mcp` command on your `PATH`.

### Option A — build a wheel, scp one file, pip install (what you want)

On the **build** machine (this repo):

```bash
cd /path/to/snmp-mcp
python3 -m pip install build
python3 -m build
# produces:
#   dist/snmp_mcp-1.0.0-py3-none-any.whl   ← copy this
#   dist/snmp_mcp-1.0.0.tar.gz             ← source archive (optional)
```

Copy the wheel to the other Mac:

```bash
scp dist/snmp_mcp-1.0.0-py3-none-any.whl othermac:~/Downloads/
```

On the **other** Mac:

```bash
# prereqs: Python 3.11+, net-snmp (brew install net-snmp)
pipx install ~/Downloads/snmp_mcp-1.0.0-py3-none-any.whl
# or without pipx:
python3 -m pip install --user ~/Downloads/snmp_mcp-1.0.0-py3-none-any.whl

which snmp-mcp
snmp-mcp --help
```

Notes:

- The `.whl` is the single installable artifact (pure Python, works on any Mac/Linux with Python 3.11+).
- `pip`/`pipx` still downloads dependencies (`mcp`, `PyYAML`) from PyPI unless you vendor those wheels too.
- Upgrade later: build a new wheel, scp, `pipx install --force ~/Downloads/snmp_mcp-….whl`.

### Option B — `pipx` / `uv` from a git clone or path

```bash
git clone <your-repo-url> snmp-mcp
cd snmp-mcp
pipx install .
# or: uv tool install .
# or: pipx install 'git+ssh://git@gitlab.com/…/snmp-mcp.git'
```

### Option C — venv + pip from source tree

```bash
cd snmp-mcp
python3 -m venv .venv && source .venv/bin/activate
pip install .
which snmp-mcp
```

### Verify install

```bash
snmp-mcp --help
# or: ~/.local/bin/snmp-mcp --help   (common pipx location)
```
---

## Config (once per machine)

```bash
mkdir -p ~/.config/snmp-mcp
cp examples/communities.yaml.example ~/.config/snmp-mcp/communities.yaml
# optional:
cp examples/hosts.yaml.example ~/.config/snmp-mcp/hosts.yaml
chmod 600 ~/.config/snmp-mcp/communities.yaml
```

Edit communities (example):

```yaml
# ~/.config/snmp-mcp/communities.yaml
communities:
  - network: 172.23.7.0/24
    community: mcp
```

Matching: **longest CIDR prefix** wins; same length → first listed. No match → tool error (no default community).

Optional hosts map:

```yaml
# ~/.config/snmp-mcp/hosts.yaml
hosts:
  tibit: 172.23.7.1
```

Smoke-test without an MCP client:

```bash
# Ensure communities file is set; this starts the MCP stdio server (Ctrl+C to stop)
snmp-mcp --communities ~/.config/snmp-mcp/communities.yaml
```

For a direct SNMP check (outside MCP):

```bash
snmpget -v2c -c mcp -t 3 172.23.7.1 SNMPv2-MIB::sysDescr.0
```

---

## Register with Claude Desktop

1. Install `snmp-mcp` so `snmp-mcp` is on your login PATH (or use the absolute path from `which snmp-mcp` / `pipx list`).
2. Open Claude Desktop → **Settings → Developer → Edit Config**  
   (or edit the file directly):

| OS | Config file |
|----|-------------|
| macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |
| Windows | `%APPDATA%\Claude\claude_desktop_config.json` |

3. Merge the `mcpServers.snmp` block (see also `examples/claude_desktop_config.snippet.json`):

```json
{
  "mcpServers": {
    "snmp": {
      "command": "snmp-mcp",
      "args": [
        "--communities",
        "/Users/YOU/.config/snmp-mcp/communities.yaml",
        "--hosts",
        "/Users/YOU/.config/snmp-mcp/hosts.yaml"
      ]
    }
  }
}
```

If Claude cannot find `snmp-mcp` (common when GUI apps don’t inherit shell PATH), use the **absolute path**:

```bash
which snmp-mcp
# e.g. /Users/YOU/.local/bin/snmp-mcp
```

```json
{
  "mcpServers": {
    "snmp": {
      "command": "/Users/YOU/.local/bin/snmp-mcp",
      "args": [
        "--communities",
        "/Users/YOU/.config/snmp-mcp/communities.yaml"
      ]
    }
  }
}
```

4. **Fully quit and restart Claude Desktop.**
5. Confirm the `snmp` server appears under Developer / MCP tools. Try: *“Use snmp_get on 172.23.7.1 for SNMPv2-MIB::sysDescr.0”*.

---

## Register with OpenCode

OpenCode reads MCP under the `mcp` key in:

- **Global:** `~/.config/opencode/opencode.json` (or `opencode.jsonc`)
- **Project:** `opencode.json` in the project root

Add a **local** server (see also `examples/opencode.mcp.snippet.json`):

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "snmp": {
      "type": "local",
      "enabled": true,
      "command": [
        "snmp-mcp",
        "--communities",
        "/Users/YOU/.config/snmp-mcp/communities.yaml",
        "--hosts",
        "/Users/YOU/.config/snmp-mcp/hosts.yaml"
      ]
    }
  }
}
```

Notes:

- `command` is a **JSON array**: binary first, then args (not a single shell string).
- Prefer absolute path to `snmp-mcp` if OpenCode’s environment is minimal.
- Optional: pass env instead of flags:

```json
{
  "mcp": {
    "snmp": {
      "type": "local",
      "enabled": true,
      "command": ["snmp-mcp"],
      "environment": {
        "SNMP_MCP_COMMUNITIES": "/Users/YOU/.config/snmp-mcp/communities.yaml",
        "SNMP_MCP_HOSTS": "/Users/YOU/.config/snmp-mcp/hosts.yaml"
      }
    }
  }
}
```

Restart OpenCode (or start a new session). List / debug MCP with OpenCode’s MCP commands if available (`opencode mcp list`).

Prompt example: *“Using snmp tools, what is sysDescr and uptime for tibit?”*

**If OpenCode shows `MCP error -32000: Connection closed`:**

1. In a terminal, `snmp-mcp --communities ~/.config/snmp-mcp/communities.yaml` should **hang with no output** (that means the server is healthy — Ctrl+C to stop).
2. Use **absolute paths** in `command` (OpenCode often has a minimal `PATH`).
3. Set `environment.PATH` to include Homebrew if net-snmp lives there (`/opt/homebrew/bin`).
4. Raise `timeout` (ms) for tool discovery, e.g. `15000`.
5. Rebuild/reinstall after upgrades (`pipx install --force …whl`).

---

## CLI flags / env

| Flag | Env | Default |
|------|-----|---------|
| `--communities` | `SNMP_MCP_COMMUNITIES` | **required** |
| `--hosts` | `SNMP_MCP_HOSTS` | none |
| `--mib-dir` | `SNMP_MCP_MIB_DIR` | bundled MIBs |
| `--timeout` | `SNMP_MCP_TIMEOUT` | `3` |
| `--retries` | `SNMP_MCP_RETRIES` | `1` |
| `--max-walk-results` | `SNMP_MCP_MAX_WALK_RESULTS` | `1000` |
| `--log-level` | `SNMP_MCP_LOG_LEVEL` | `WARNING` |

---

## Tools

- **`snmp_get(hosts, oids, port?)`** — one host or list; one OID or list  
- **`snmp_walk(hosts, oid, port?, max_results?)`** — capped walk; `truncated: true` if cut  

### Common OIDs

| Question | OID |
|----------|-----|
| Uptime | `SNMPv2-MIB::sysUpTime.0` |
| OS / description | `SNMPv2-MIB::sysDescr.0` |
| System name | `SNMPv2-MIB::sysName.0` |
| Interfaces | walk `IF-MIB::ifDescr` |

### Private / enterprise MIBs

Bundled MIBs cover standard system/IF. For private trees (e.g. Pavlov under
`enterprises.29941`):

```bash
# Option 1: personal dir (auto-loaded if present)
mkdir -p ~/.config/snmp-mcp/mibs
cp private-mibs/*.txt ~/.config/snmp-mcp/mibs/

# Option 2: explicit flag
snmp-mcp --communities ... --mib-dir /path/to/private-mibs
```

See `private-mibs/README.md` for module names and example OIDs
(`PAVLOV-DOCKER::dockerRunning`, `PAVLOV-BIRD::birdRunning`, …).

net-snmp expects **`.txt`** files whose names match the MIB module.

---

## Dev install & tests

```bash
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
pytest
```

---

## Troubleshooting

| Symptom | Fix |
|---------|-----|
| `net-snmp tools not found` | Install net-snmp; ensure `snmpget`/`snmpwalk` on PATH for the MCP process |
| Claude/OpenCode: server fails to start | Use **absolute path** to `snmp-mcp`; check communities file path |
| `no community rule matches` | Host IP not covered by any CIDR in YAML |
| SNMP timeout | Wrong IP, community, firewall, or device down; test with bare `snmpget` first |
| Named OIDs fail | Bundled MIBs missing from install — reinstall package; or pass `--mib-dir` |

---

## Implementation notes

- **Language:** Python MVP; Kotlin possible later (same contracts). See PRD.  
- **SNMP engine (feature/pysnmp):** **pysnmp** by default; **net-snmp CLI** via `--backend netsnmp`.  
- **Package:** import `org.dempsay.mcp.snmp`; console script `snmp-mcp`.  
- **Secrets:** keep `communities.yaml` out of git; mode `600`.