snmp-mcp
by sdempsay
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`.
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues