mcp-llmnetops 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mcp_llmnetops-0.1.1/.github/workflows/python-publish.yml +70 -0
- mcp_llmnetops-0.1.1/.gitignore +27 -0
- mcp_llmnetops-0.1.1/LICENSE +21 -0
- mcp_llmnetops-0.1.1/PKG-INFO +242 -0
- mcp_llmnetops-0.1.1/README.md +218 -0
- mcp_llmnetops-0.1.1/devices.example.yaml +57 -0
- mcp_llmnetops-0.1.1/pyproject.toml +43 -0
- mcp_llmnetops-0.1.1/src/mcp_llmnetops/__init__.py +3 -0
- mcp_llmnetops-0.1.1/src/mcp_llmnetops/__main__.py +4 -0
- mcp_llmnetops-0.1.1/src/mcp_llmnetops/config.py +123 -0
- mcp_llmnetops-0.1.1/src/mcp_llmnetops/platforms.py +281 -0
- mcp_llmnetops-0.1.1/src/mcp_llmnetops/server.py +360 -0
- mcp_llmnetops-0.1.1/src/mcp_llmnetops/ssh_client.py +185 -0
- mcp_llmnetops-0.1.1/tests/test_platforms.py +197 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# This workflow will upload a Python Package to PyPI when a release is created
|
|
2
|
+
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries
|
|
3
|
+
|
|
4
|
+
# This workflow uses actions that are not certified by GitHub.
|
|
5
|
+
# They are provided by a third-party and are governed by
|
|
6
|
+
# separate terms of service, privacy policy, and support
|
|
7
|
+
# documentation.
|
|
8
|
+
|
|
9
|
+
name: Upload Python Package
|
|
10
|
+
|
|
11
|
+
on:
|
|
12
|
+
release:
|
|
13
|
+
types: [published]
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
contents: read
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
release-build:
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v4
|
|
24
|
+
|
|
25
|
+
- uses: actions/setup-python@v5
|
|
26
|
+
with:
|
|
27
|
+
python-version: "3.x"
|
|
28
|
+
|
|
29
|
+
- name: Build release distributions
|
|
30
|
+
run: |
|
|
31
|
+
# NOTE: put your own distribution build steps here.
|
|
32
|
+
python -m pip install build
|
|
33
|
+
python -m build
|
|
34
|
+
|
|
35
|
+
- name: Upload distributions
|
|
36
|
+
uses: actions/upload-artifact@v4
|
|
37
|
+
with:
|
|
38
|
+
name: release-dists
|
|
39
|
+
path: dist/
|
|
40
|
+
|
|
41
|
+
pypi-publish:
|
|
42
|
+
runs-on: ubuntu-latest
|
|
43
|
+
needs:
|
|
44
|
+
- release-build
|
|
45
|
+
permissions:
|
|
46
|
+
# IMPORTANT: this permission is mandatory for trusted publishing
|
|
47
|
+
id-token: write
|
|
48
|
+
|
|
49
|
+
# Dedicated environments with protections for publishing are strongly recommended.
|
|
50
|
+
# For more information, see: https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#deployment-protection-rules
|
|
51
|
+
environment:
|
|
52
|
+
name: pypi
|
|
53
|
+
# OPTIONAL: uncomment and update to include your PyPI project URL in the deployment status:
|
|
54
|
+
# url: https://pypi.org/p/YOURPROJECT
|
|
55
|
+
#
|
|
56
|
+
# ALTERNATIVE: if your GitHub Release name is the PyPI project version string
|
|
57
|
+
# ALTERNATIVE: exactly, uncomment the following line instead:
|
|
58
|
+
# url: https://pypi.org/project/YOURPROJECT/${{ github.event.release.name }}
|
|
59
|
+
|
|
60
|
+
steps:
|
|
61
|
+
- name: Retrieve release distributions
|
|
62
|
+
uses: actions/download-artifact@v4
|
|
63
|
+
with:
|
|
64
|
+
name: release-dists
|
|
65
|
+
path: dist/
|
|
66
|
+
|
|
67
|
+
- name: Publish release distributions to PyPI
|
|
68
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
69
|
+
with:
|
|
70
|
+
packages-dir: dist/
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
build/
|
|
6
|
+
dist/
|
|
7
|
+
.eggs/
|
|
8
|
+
|
|
9
|
+
# Environments
|
|
10
|
+
.venv/
|
|
11
|
+
venv/
|
|
12
|
+
|
|
13
|
+
# Tooling
|
|
14
|
+
.pytest_cache/
|
|
15
|
+
.mypy_cache/
|
|
16
|
+
.ruff_cache/
|
|
17
|
+
.coverage
|
|
18
|
+
htmlcov/
|
|
19
|
+
|
|
20
|
+
# Local config (contains credentials!)
|
|
21
|
+
devices.yaml
|
|
22
|
+
devices.yml
|
|
23
|
+
known_hosts
|
|
24
|
+
|
|
25
|
+
# IDE
|
|
26
|
+
.vscode/
|
|
27
|
+
.idea/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 mcp-llmnetops contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: mcp-llmnetops
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: MCP server for read-only network device operations (MikroTik, Cisco, Juniper, Aruba, Huawei, Ruckus)
|
|
5
|
+
License: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Keywords: aruba,cisco,huawei,juniper,mcp,mikrotik,model-context-protocol,netops,network,ruckus
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Intended Audience :: System Administrators
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Topic :: System :: Networking
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Requires-Dist: asyncssh>=2.14
|
|
18
|
+
Requires-Dist: fastmcp>=2.10
|
|
19
|
+
Requires-Dist: pyyaml>=6.0
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
22
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# mcp-llmnetops
|
|
26
|
+
|
|
27
|
+
MCP (Model Context Protocol) server untuk operasi **read-only** pada perangkat jaringan.
|
|
28
|
+
LLM (Claude, Copilot, dll.) bisa melihat routing table, interface, BGP, log, config, dan ping
|
|
29
|
+
perangkat jaringan Anda — hanya melalui daftar perintah yang di-whitelist per platform.
|
|
30
|
+
|
|
31
|
+
## Platform yang didukung
|
|
32
|
+
|
|
33
|
+
| Platform key | Vendor / OS | Contoh perintah |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| `mikrotik-ros6` | MikroTik RouterOS 6 | `/ip route print`, `/routing bgp peer print`, `/export` |
|
|
36
|
+
| `mikrotik-ros7` | MikroTik RouterOS 7 | `/ip route print`, `/routing bgp session print`, `/export` |
|
|
37
|
+
| `cisco-ios` | Cisco IOS | `show ip route`, `show ip bgp summary` |
|
|
38
|
+
| `cisco-iosxe` | Cisco IOS XE | `show ip route`, `show ip bgp summary` |
|
|
39
|
+
| `cisco-iosxr` | Cisco IOS XR | `show route`, `show bgp summary` |
|
|
40
|
+
| `cisco-nxos` | Cisco NX-OS | `show ip route`, `show ip bgp summary` |
|
|
41
|
+
| `juniper-junos` | Juniper Junos | `show route`, `show bgp neighbor` |
|
|
42
|
+
| `aruba-aos-cx` | Aruba AOS-CX | `show ip route`, `show bgp summary` |
|
|
43
|
+
| `huawei-vrp` | Huawei VRP | `display ip routing-table`, `display bgp peer` |
|
|
44
|
+
| `ruckus-fastiron` | Ruckus FastIron | `show ip route`, `show ip bgp summary` |
|
|
45
|
+
|
|
46
|
+
Setiap platform hanya bisa menjalankan perintah yang terdaftar di
|
|
47
|
+
[`src/mcp_llmnetops/platforms.py`](src/mcp_llmnetops/platforms.py) — perintah lain ditolak.
|
|
48
|
+
Perintah `ping` membutuhkan parameter `target`.
|
|
49
|
+
|
|
50
|
+
## Instalasi
|
|
51
|
+
|
|
52
|
+
### Dengan pipx
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pipx install mcp-llmnetops
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Dari source
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
git clone https://github.com/ratnoub/mcp-llmnetops.git
|
|
62
|
+
cd mcp-llmnetops
|
|
63
|
+
pipx install .
|
|
64
|
+
# atau untuk development:
|
|
65
|
+
python -m venv .venv && . .venv/Scripts/activate # Windows
|
|
66
|
+
pip install -e ".[dev]"
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Konfigurasi device
|
|
70
|
+
|
|
71
|
+
Salin `devices.example.yaml` menjadi `devices.yaml` dan isi dengan device Anda:
|
|
72
|
+
|
|
73
|
+
```yaml
|
|
74
|
+
devices:
|
|
75
|
+
- name: mikrotik-core-01
|
|
76
|
+
host: 192.168.1.1
|
|
77
|
+
platform: mikrotik-ros7
|
|
78
|
+
username: admin
|
|
79
|
+
password: ${MIKROTIK_CORE01_PASSWORD} # dari environment variable
|
|
80
|
+
|
|
81
|
+
- name: cisco-edge-01
|
|
82
|
+
host: 10.0.0.1
|
|
83
|
+
platform: cisco-ios
|
|
84
|
+
username: netops
|
|
85
|
+
password: ${CISCO_EDGE01_PASSWORD}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Field yang tersedia per device:
|
|
89
|
+
|
|
90
|
+
| Field | Wajib | Default | Keterangan |
|
|
91
|
+
|---|---|---|---|
|
|
92
|
+
| `name` | ya | — | Nama unik device (dipakai LLM) |
|
|
93
|
+
| `host` | ya | — | IP atau hostname |
|
|
94
|
+
| `platform` | ya | — | Salah satu platform key di tabel di atas |
|
|
95
|
+
| `username` | ya | — | Username SSH |
|
|
96
|
+
| `password` | salah satu | — | Password SSH (atau `ssh_key`) |
|
|
97
|
+
| `ssh_key` | salah satu | — | Path ke file private key SSH |
|
|
98
|
+
| `port` | tidak | `22` | Port SSH |
|
|
99
|
+
| `timeout` | tidak | `60` | Timeout per perintah (detik) |
|
|
100
|
+
| `known_hosts` | tidak | `auto` | `auto` (simpan key baru), `strict` (`~/.ssh/known_hosts`), `no-check` |
|
|
101
|
+
|
|
102
|
+
Nilai string bisa memakai environment variable: `${NAMA_VAR}`.
|
|
103
|
+
|
|
104
|
+
**Lokasi file config** (urutan pencarian):
|
|
105
|
+
1. `--config <path>`
|
|
106
|
+
2. Environment variable `MCP_LLMNETOPS_CONFIG`
|
|
107
|
+
3. `./devices.yaml` (working directory)
|
|
108
|
+
4. `~/.config/mcp-llmnetops/devices.yaml`
|
|
109
|
+
|
|
110
|
+
## Registrasi ke MCP client
|
|
111
|
+
|
|
112
|
+
### Claude Desktop / Claude Code
|
|
113
|
+
|
|
114
|
+
```json
|
|
115
|
+
{
|
|
116
|
+
"mcpServers": {
|
|
117
|
+
"llmnetops": {
|
|
118
|
+
"command": "mcp-llmnetops",
|
|
119
|
+
"args": ["--transport", "stdio", "--config", "C:/path/to/devices.yaml"],
|
|
120
|
+
"env": {
|
|
121
|
+
"MIKROTIK_CORE01_PASSWORD": "rahasia",
|
|
122
|
+
"CISCO_EDGE01_PASSWORD": "rahasia"
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Copilot CLI / client lain (stdio)
|
|
130
|
+
|
|
131
|
+
```json
|
|
132
|
+
{
|
|
133
|
+
"mcpServers": {
|
|
134
|
+
"llmnetops": {
|
|
135
|
+
"command": "mcp-llmnetops",
|
|
136
|
+
"args": ["--transport", "stdio"],
|
|
137
|
+
"env": {
|
|
138
|
+
"MCP_LLMNETOPS_CONFIG": "C:/path/to/devices.yaml"
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Akses via HTTP (streamable-http)
|
|
146
|
+
|
|
147
|
+
Secara default server berjalan sebagai **HTTP server** di port **5758**,
|
|
148
|
+
bisa diakses di `http://<IP>:5758/mcp`. Cocok untuk client MCP yang mendukung
|
|
149
|
+
transport streamable-HTTP.
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
# jalankan server (default sudah streamable-http di 0.0.0.0:5758)
|
|
153
|
+
mcp-llmnetops --config devices.yaml
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Client MCP cukup menunjuk ke endpoint:
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
http://<IP-server>:5758/mcp
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
> Catatan: karena default-nya HTTP, client berbasis **stdio** (Claude Desktop,
|
|
163
|
+
> Copilot CLI) harus menambahkan `--transport stdio` seperti contoh di atas.
|
|
164
|
+
|
|
165
|
+
## Tools yang tersedia
|
|
166
|
+
|
|
167
|
+
Setiap perintah whitelisted terdaftar sebagai **tool MCP tersendiri** (satu tool per
|
|
168
|
+
platform × perintah), sehingga LLM cukup memanggil tool yang tepat tanpa perlu
|
|
169
|
+
menyebutkan string perintah. Total **95 tool**: 3 tool umum + 92 tool per-perintah.
|
|
170
|
+
|
|
171
|
+
### Tool umum
|
|
172
|
+
|
|
173
|
+
| Tool | Fungsi |
|
|
174
|
+
|---|---|
|
|
175
|
+
| `list_devices` | Daftar device yang terkonfigurasi |
|
|
176
|
+
| `list_platforms` | Daftar platform yang didukung |
|
|
177
|
+
| `test_connection(device)` | Tes koneksi SSH ke device |
|
|
178
|
+
|
|
179
|
+
### Tool per-perintah
|
|
180
|
+
|
|
181
|
+
Nama tool mengikuti skema `<platform>_<perintah>`, dengan platform key memakai
|
|
182
|
+
underscore (mis. `cisco-ios` → `cisco_ios`, `aruba-aos-cx` → `aruba_aos_cx`).
|
|
183
|
+
Semua tool menerima parameter `device` (nama device dari `list_devices`).
|
|
184
|
+
Tool `ping` tambahan menerima parameter wajib `target`.
|
|
185
|
+
|
|
186
|
+
Contoh nama tool:
|
|
187
|
+
|
|
188
|
+
| Tool | Perintah yang dijalankan |
|
|
189
|
+
|---|---|
|
|
190
|
+
| `mikrotik_ros7_ip_route_print` | `/ip route print` |
|
|
191
|
+
| `mikrotik_ros7_routing_bgp_session_print` | `/routing bgp session print` |
|
|
192
|
+
| `cisco_ios_show_ip_route` | `show ip route` |
|
|
193
|
+
| `cisco_ios_show_ip_bgp_summary` | `show ip bgp summary` |
|
|
194
|
+
| `cisco_iosxr_show_route` | `show route` |
|
|
195
|
+
| `juniper_junos_show_bgp_neighbor` | `show bgp neighbor` |
|
|
196
|
+
| `huawei_vrp_display_ip_routing_table` | `display ip routing-table` |
|
|
197
|
+
| `aruba_aos_cx_show_bgp` | `show bgp` |
|
|
198
|
+
| `cisco_ios_ping` | `ping <target>` |
|
|
199
|
+
|
|
200
|
+
Contoh alur penggunaan oleh LLM:
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
list_devices()
|
|
204
|
+
→ "- mikrotik-core-01: 192.168.1.1:22 [mikrotik-ros7] user=admin"
|
|
205
|
+
|
|
206
|
+
mikrotik_ros7_ip_route_print(device="mikrotik-core-01")
|
|
207
|
+
→ "<routing table output>"
|
|
208
|
+
|
|
209
|
+
cisco_ios_ping(device="cisco-edge-01", target="8.8.8.8")
|
|
210
|
+
→ "<ping output>"
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Keamanan
|
|
214
|
+
|
|
215
|
+
- **Whitelist ketat**: hanya perintah yang terdaftar per platform yang bisa dijalankan.
|
|
216
|
+
Tidak ada eksekusi perintah arbitrer.
|
|
217
|
+
- **Read-only**: semua perintah yang diizinkan bersifat read-only (show/print/display/ping).
|
|
218
|
+
- **Kredensial**: disarankan memakai environment variable (`${VAR}`) alih-alih plaintext.
|
|
219
|
+
- **SSH host key**: mode `auto` menyimpan host key baru di
|
|
220
|
+
`~/.config/mcp-llmnetops/known_hosts`; gunakan `strict` untuk verifikasi ketat.
|
|
221
|
+
- File `devices.yaml` mengandung kredensial — jangan di-commit (sudah ada di `.gitignore`).
|
|
222
|
+
|
|
223
|
+
## Development
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
pip install -e ".[dev]"
|
|
227
|
+
pytest
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Jalankan server manual:
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
mcp-llmnetops --config devices.yaml # HTTP di http://0.0.0.0:5758/mcp (default)
|
|
234
|
+
mcp-llmnetops --transport stdio # stdio (untuk client yang launch proses)
|
|
235
|
+
mcp-llmnetops --port 9999 # ganti port HTTP
|
|
236
|
+
mcp-llmnetops --host 127.0.0.1 # bind ke localhost saja
|
|
237
|
+
mcp-llmnetops --version
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Lisensi
|
|
241
|
+
|
|
242
|
+
MIT
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# mcp-llmnetops
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server untuk operasi **read-only** pada perangkat jaringan.
|
|
4
|
+
LLM (Claude, Copilot, dll.) bisa melihat routing table, interface, BGP, log, config, dan ping
|
|
5
|
+
perangkat jaringan Anda — hanya melalui daftar perintah yang di-whitelist per platform.
|
|
6
|
+
|
|
7
|
+
## Platform yang didukung
|
|
8
|
+
|
|
9
|
+
| Platform key | Vendor / OS | Contoh perintah |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| `mikrotik-ros6` | MikroTik RouterOS 6 | `/ip route print`, `/routing bgp peer print`, `/export` |
|
|
12
|
+
| `mikrotik-ros7` | MikroTik RouterOS 7 | `/ip route print`, `/routing bgp session print`, `/export` |
|
|
13
|
+
| `cisco-ios` | Cisco IOS | `show ip route`, `show ip bgp summary` |
|
|
14
|
+
| `cisco-iosxe` | Cisco IOS XE | `show ip route`, `show ip bgp summary` |
|
|
15
|
+
| `cisco-iosxr` | Cisco IOS XR | `show route`, `show bgp summary` |
|
|
16
|
+
| `cisco-nxos` | Cisco NX-OS | `show ip route`, `show ip bgp summary` |
|
|
17
|
+
| `juniper-junos` | Juniper Junos | `show route`, `show bgp neighbor` |
|
|
18
|
+
| `aruba-aos-cx` | Aruba AOS-CX | `show ip route`, `show bgp summary` |
|
|
19
|
+
| `huawei-vrp` | Huawei VRP | `display ip routing-table`, `display bgp peer` |
|
|
20
|
+
| `ruckus-fastiron` | Ruckus FastIron | `show ip route`, `show ip bgp summary` |
|
|
21
|
+
|
|
22
|
+
Setiap platform hanya bisa menjalankan perintah yang terdaftar di
|
|
23
|
+
[`src/mcp_llmnetops/platforms.py`](src/mcp_llmnetops/platforms.py) — perintah lain ditolak.
|
|
24
|
+
Perintah `ping` membutuhkan parameter `target`.
|
|
25
|
+
|
|
26
|
+
## Instalasi
|
|
27
|
+
|
|
28
|
+
### Dengan pipx
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pipx install mcp-llmnetops
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Dari source
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
git clone https://github.com/ratnoub/mcp-llmnetops.git
|
|
38
|
+
cd mcp-llmnetops
|
|
39
|
+
pipx install .
|
|
40
|
+
# atau untuk development:
|
|
41
|
+
python -m venv .venv && . .venv/Scripts/activate # Windows
|
|
42
|
+
pip install -e ".[dev]"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Konfigurasi device
|
|
46
|
+
|
|
47
|
+
Salin `devices.example.yaml` menjadi `devices.yaml` dan isi dengan device Anda:
|
|
48
|
+
|
|
49
|
+
```yaml
|
|
50
|
+
devices:
|
|
51
|
+
- name: mikrotik-core-01
|
|
52
|
+
host: 192.168.1.1
|
|
53
|
+
platform: mikrotik-ros7
|
|
54
|
+
username: admin
|
|
55
|
+
password: ${MIKROTIK_CORE01_PASSWORD} # dari environment variable
|
|
56
|
+
|
|
57
|
+
- name: cisco-edge-01
|
|
58
|
+
host: 10.0.0.1
|
|
59
|
+
platform: cisco-ios
|
|
60
|
+
username: netops
|
|
61
|
+
password: ${CISCO_EDGE01_PASSWORD}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Field yang tersedia per device:
|
|
65
|
+
|
|
66
|
+
| Field | Wajib | Default | Keterangan |
|
|
67
|
+
|---|---|---|---|
|
|
68
|
+
| `name` | ya | — | Nama unik device (dipakai LLM) |
|
|
69
|
+
| `host` | ya | — | IP atau hostname |
|
|
70
|
+
| `platform` | ya | — | Salah satu platform key di tabel di atas |
|
|
71
|
+
| `username` | ya | — | Username SSH |
|
|
72
|
+
| `password` | salah satu | — | Password SSH (atau `ssh_key`) |
|
|
73
|
+
| `ssh_key` | salah satu | — | Path ke file private key SSH |
|
|
74
|
+
| `port` | tidak | `22` | Port SSH |
|
|
75
|
+
| `timeout` | tidak | `60` | Timeout per perintah (detik) |
|
|
76
|
+
| `known_hosts` | tidak | `auto` | `auto` (simpan key baru), `strict` (`~/.ssh/known_hosts`), `no-check` |
|
|
77
|
+
|
|
78
|
+
Nilai string bisa memakai environment variable: `${NAMA_VAR}`.
|
|
79
|
+
|
|
80
|
+
**Lokasi file config** (urutan pencarian):
|
|
81
|
+
1. `--config <path>`
|
|
82
|
+
2. Environment variable `MCP_LLMNETOPS_CONFIG`
|
|
83
|
+
3. `./devices.yaml` (working directory)
|
|
84
|
+
4. `~/.config/mcp-llmnetops/devices.yaml`
|
|
85
|
+
|
|
86
|
+
## Registrasi ke MCP client
|
|
87
|
+
|
|
88
|
+
### Claude Desktop / Claude Code
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
{
|
|
92
|
+
"mcpServers": {
|
|
93
|
+
"llmnetops": {
|
|
94
|
+
"command": "mcp-llmnetops",
|
|
95
|
+
"args": ["--transport", "stdio", "--config", "C:/path/to/devices.yaml"],
|
|
96
|
+
"env": {
|
|
97
|
+
"MIKROTIK_CORE01_PASSWORD": "rahasia",
|
|
98
|
+
"CISCO_EDGE01_PASSWORD": "rahasia"
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Copilot CLI / client lain (stdio)
|
|
106
|
+
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"mcpServers": {
|
|
110
|
+
"llmnetops": {
|
|
111
|
+
"command": "mcp-llmnetops",
|
|
112
|
+
"args": ["--transport", "stdio"],
|
|
113
|
+
"env": {
|
|
114
|
+
"MCP_LLMNETOPS_CONFIG": "C:/path/to/devices.yaml"
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Akses via HTTP (streamable-http)
|
|
122
|
+
|
|
123
|
+
Secara default server berjalan sebagai **HTTP server** di port **5758**,
|
|
124
|
+
bisa diakses di `http://<IP>:5758/mcp`. Cocok untuk client MCP yang mendukung
|
|
125
|
+
transport streamable-HTTP.
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# jalankan server (default sudah streamable-http di 0.0.0.0:5758)
|
|
129
|
+
mcp-llmnetops --config devices.yaml
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Client MCP cukup menunjuk ke endpoint:
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
http://<IP-server>:5758/mcp
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
> Catatan: karena default-nya HTTP, client berbasis **stdio** (Claude Desktop,
|
|
139
|
+
> Copilot CLI) harus menambahkan `--transport stdio` seperti contoh di atas.
|
|
140
|
+
|
|
141
|
+
## Tools yang tersedia
|
|
142
|
+
|
|
143
|
+
Setiap perintah whitelisted terdaftar sebagai **tool MCP tersendiri** (satu tool per
|
|
144
|
+
platform × perintah), sehingga LLM cukup memanggil tool yang tepat tanpa perlu
|
|
145
|
+
menyebutkan string perintah. Total **95 tool**: 3 tool umum + 92 tool per-perintah.
|
|
146
|
+
|
|
147
|
+
### Tool umum
|
|
148
|
+
|
|
149
|
+
| Tool | Fungsi |
|
|
150
|
+
|---|---|
|
|
151
|
+
| `list_devices` | Daftar device yang terkonfigurasi |
|
|
152
|
+
| `list_platforms` | Daftar platform yang didukung |
|
|
153
|
+
| `test_connection(device)` | Tes koneksi SSH ke device |
|
|
154
|
+
|
|
155
|
+
### Tool per-perintah
|
|
156
|
+
|
|
157
|
+
Nama tool mengikuti skema `<platform>_<perintah>`, dengan platform key memakai
|
|
158
|
+
underscore (mis. `cisco-ios` → `cisco_ios`, `aruba-aos-cx` → `aruba_aos_cx`).
|
|
159
|
+
Semua tool menerima parameter `device` (nama device dari `list_devices`).
|
|
160
|
+
Tool `ping` tambahan menerima parameter wajib `target`.
|
|
161
|
+
|
|
162
|
+
Contoh nama tool:
|
|
163
|
+
|
|
164
|
+
| Tool | Perintah yang dijalankan |
|
|
165
|
+
|---|---|
|
|
166
|
+
| `mikrotik_ros7_ip_route_print` | `/ip route print` |
|
|
167
|
+
| `mikrotik_ros7_routing_bgp_session_print` | `/routing bgp session print` |
|
|
168
|
+
| `cisco_ios_show_ip_route` | `show ip route` |
|
|
169
|
+
| `cisco_ios_show_ip_bgp_summary` | `show ip bgp summary` |
|
|
170
|
+
| `cisco_iosxr_show_route` | `show route` |
|
|
171
|
+
| `juniper_junos_show_bgp_neighbor` | `show bgp neighbor` |
|
|
172
|
+
| `huawei_vrp_display_ip_routing_table` | `display ip routing-table` |
|
|
173
|
+
| `aruba_aos_cx_show_bgp` | `show bgp` |
|
|
174
|
+
| `cisco_ios_ping` | `ping <target>` |
|
|
175
|
+
|
|
176
|
+
Contoh alur penggunaan oleh LLM:
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
list_devices()
|
|
180
|
+
→ "- mikrotik-core-01: 192.168.1.1:22 [mikrotik-ros7] user=admin"
|
|
181
|
+
|
|
182
|
+
mikrotik_ros7_ip_route_print(device="mikrotik-core-01")
|
|
183
|
+
→ "<routing table output>"
|
|
184
|
+
|
|
185
|
+
cisco_ios_ping(device="cisco-edge-01", target="8.8.8.8")
|
|
186
|
+
→ "<ping output>"
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Keamanan
|
|
190
|
+
|
|
191
|
+
- **Whitelist ketat**: hanya perintah yang terdaftar per platform yang bisa dijalankan.
|
|
192
|
+
Tidak ada eksekusi perintah arbitrer.
|
|
193
|
+
- **Read-only**: semua perintah yang diizinkan bersifat read-only (show/print/display/ping).
|
|
194
|
+
- **Kredensial**: disarankan memakai environment variable (`${VAR}`) alih-alih plaintext.
|
|
195
|
+
- **SSH host key**: mode `auto` menyimpan host key baru di
|
|
196
|
+
`~/.config/mcp-llmnetops/known_hosts`; gunakan `strict` untuk verifikasi ketat.
|
|
197
|
+
- File `devices.yaml` mengandung kredensial — jangan di-commit (sudah ada di `.gitignore`).
|
|
198
|
+
|
|
199
|
+
## Development
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
pip install -e ".[dev]"
|
|
203
|
+
pytest
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Jalankan server manual:
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
mcp-llmnetops --config devices.yaml # HTTP di http://0.0.0.0:5758/mcp (default)
|
|
210
|
+
mcp-llmnetops --transport stdio # stdio (untuk client yang launch proses)
|
|
211
|
+
mcp-llmnetops --port 9999 # ganti port HTTP
|
|
212
|
+
mcp-llmnetops --host 127.0.0.1 # bind ke localhost saja
|
|
213
|
+
mcp-llmnetops --version
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Lisensi
|
|
217
|
+
|
|
218
|
+
MIT
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Example device configuration for mcp-llmnetops.
|
|
2
|
+
#
|
|
3
|
+
# Copy this file to devices.yaml and fill in real values.
|
|
4
|
+
# String values may reference environment variables: ${VAR_NAME}
|
|
5
|
+
#
|
|
6
|
+
# Config file resolution order:
|
|
7
|
+
# 1. --config <path>
|
|
8
|
+
# 2. $MCP_LLMNETOPS_CONFIG
|
|
9
|
+
# 3. ./devices.yaml (current working directory)
|
|
10
|
+
# 4. ~/.config/mcp-llmnetops/devices.yaml
|
|
11
|
+
|
|
12
|
+
devices:
|
|
13
|
+
# --- MikroTik ---------------------------------------------------------
|
|
14
|
+
- name: mikrotik-core-01
|
|
15
|
+
host: 192.168.1.1
|
|
16
|
+
platform: mikrotik-ros7 # or: mikrotik-ros6
|
|
17
|
+
username: admin
|
|
18
|
+
password: ${MIKROTIK_CORE01_PASSWORD}
|
|
19
|
+
# port: 22
|
|
20
|
+
# ssh_key: ~/.ssh/id_ed25519 # alternative to password
|
|
21
|
+
# timeout: 60 # per-command timeout in seconds
|
|
22
|
+
# known_hosts: auto # auto | strict | no-check
|
|
23
|
+
|
|
24
|
+
# --- Cisco ------------------------------------------------------------
|
|
25
|
+
- name: cisco-edge-01
|
|
26
|
+
host: 10.0.0.1
|
|
27
|
+
platform: cisco-ios # or: cisco-iosxe, cisco-iosxr, cisco-nxos
|
|
28
|
+
username: netops
|
|
29
|
+
password: ${CISCO_EDGE01_PASSWORD}
|
|
30
|
+
|
|
31
|
+
# --- Juniper ----------------------------------------------------------
|
|
32
|
+
- name: juniper-spine-01
|
|
33
|
+
host: 10.0.0.2
|
|
34
|
+
platform: juniper-junos
|
|
35
|
+
username: netops
|
|
36
|
+
password: ${JUNIPER_SPINE01_PASSWORD}
|
|
37
|
+
|
|
38
|
+
# --- Aruba ------------------------------------------------------------
|
|
39
|
+
- name: aruba-switch-01
|
|
40
|
+
host: 10.0.0.3
|
|
41
|
+
platform: aruba-aos-cx
|
|
42
|
+
username: netops
|
|
43
|
+
password: ${ARUBA_SWITCH01_PASSWORD}
|
|
44
|
+
|
|
45
|
+
# --- Huawei -----------------------------------------------------------
|
|
46
|
+
- name: huawei-access-01
|
|
47
|
+
host: 10.0.0.4
|
|
48
|
+
platform: huawei-vrp
|
|
49
|
+
username: netops
|
|
50
|
+
password: ${HUAWEI_ACCESS01_PASSWORD}
|
|
51
|
+
|
|
52
|
+
# --- Ruckus -----------------------------------------------------------
|
|
53
|
+
- name: ruckus-switch-01
|
|
54
|
+
host: 10.0.0.5
|
|
55
|
+
platform: ruckus-fastiron
|
|
56
|
+
username: netops
|
|
57
|
+
password: ${RUCKUS_SWITCH01_PASSWORD}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "mcp-llmnetops"
|
|
7
|
+
version = "0.1.1"
|
|
8
|
+
description = "MCP server for read-only network device operations (MikroTik, Cisco, Juniper, Aruba, Huawei, Ruckus)"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
keywords = ["mcp", "model-context-protocol", "network", "netops", "mikrotik", "cisco", "juniper", "aruba", "huawei", "ruckus"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 4 - Beta",
|
|
15
|
+
"Intended Audience :: System Administrators",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3.10",
|
|
18
|
+
"Programming Language :: Python :: 3.11",
|
|
19
|
+
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Programming Language :: Python :: 3.13",
|
|
21
|
+
"Topic :: System :: Networking",
|
|
22
|
+
]
|
|
23
|
+
dependencies = [
|
|
24
|
+
"fastmcp>=2.10",
|
|
25
|
+
"asyncssh>=2.14",
|
|
26
|
+
"PyYAML>=6.0",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[project.optional-dependencies]
|
|
30
|
+
dev = [
|
|
31
|
+
"pytest>=8.0",
|
|
32
|
+
"pytest-asyncio>=0.23",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[project.scripts]
|
|
36
|
+
mcp-llmnetops = "mcp_llmnetops.server:main"
|
|
37
|
+
|
|
38
|
+
[tool.hatch.build.targets.wheel]
|
|
39
|
+
packages = ["src/mcp_llmnetops"]
|
|
40
|
+
|
|
41
|
+
[tool.pytest.ini_options]
|
|
42
|
+
asyncio_mode = "auto"
|
|
43
|
+
testpaths = ["tests"]
|