@aristanetworks/eos-mcp-server 0.6.1-beta
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.
- package/CHANGELOG.md +56 -0
- package/LICENSE +203 -0
- package/README.md +652 -0
- package/dist/cli.d.ts +16 -0
- package/dist/cli.js +188 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/printServerInfo.d.ts +2 -0
- package/dist/commands/printServerInfo.js +14 -0
- package/dist/commands/printServerInfo.js.map +1 -0
- package/dist/commands/probe.d.ts +2 -0
- package/dist/commands/probe.js +26 -0
- package/dist/commands/probe.js.map +1 -0
- package/dist/commands/validateInventory.d.ts +9 -0
- package/dist/commands/validateInventory.js +59 -0
- package/dist/commands/validateInventory.js.map +1 -0
- package/dist/config/loadConfig.d.ts +3 -0
- package/dist/config/loadConfig.js +84 -0
- package/dist/config/loadConfig.js.map +1 -0
- package/dist/config/schema.d.ts +151 -0
- package/dist/config/schema.js +54 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/configuration/getRunningConfig.d.ts +24 -0
- package/dist/configuration/getRunningConfig.js +38 -0
- package/dist/configuration/getRunningConfig.js.map +1 -0
- package/dist/connection/eosDeviceReader.d.ts +18 -0
- package/dist/connection/eosDeviceReader.js +13 -0
- package/dist/connection/eosDeviceReader.js.map +1 -0
- package/dist/connection/resolveConnection.d.ts +4 -0
- package/dist/connection/resolveConnection.js +58 -0
- package/dist/connection/resolveConnection.js.map +1 -0
- package/dist/connection/validateStartupConnections.d.ts +4 -0
- package/dist/connection/validateStartupConnections.js +28 -0
- package/dist/connection/validateStartupConnections.js.map +1 -0
- package/dist/core/errors.d.ts +8 -0
- package/dist/core/errors.js +22 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/version.d.ts +2 -0
- package/dist/core/version.js +7 -0
- package/dist/core/version.js.map +1 -0
- package/dist/eapi/client.d.ts +8 -0
- package/dist/eapi/client.js +159 -0
- package/dist/eapi/client.js.map +1 -0
- package/dist/eapi/commands.d.ts +2 -0
- package/dist/eapi/commands.js +25 -0
- package/dist/eapi/commands.js.map +1 -0
- package/dist/eapi/transport.d.ts +21 -0
- package/dist/eapi/transport.js +143 -0
- package/dist/eapi/transport.js.map +1 -0
- package/dist/eapi/types.d.ts +49 -0
- package/dist/eapi/types.js +15 -0
- package/dist/eapi/types.js.map +1 -0
- package/dist/facts/getFacts.d.ts +33 -0
- package/dist/facts/getFacts.js +50 -0
- package/dist/facts/getFacts.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +66 -0
- package/dist/index.js.map +1 -0
- package/dist/inventory/buildModel.d.ts +3 -0
- package/dist/inventory/buildModel.js +79 -0
- package/dist/inventory/buildModel.js.map +1 -0
- package/dist/inventory/effectiveVars.d.ts +2 -0
- package/dist/inventory/effectiveVars.js +52 -0
- package/dist/inventory/effectiveVars.js.map +1 -0
- package/dist/inventory/graph.d.ts +6 -0
- package/dist/inventory/graph.js +81 -0
- package/dist/inventory/graph.js.map +1 -0
- package/dist/inventory/internalTypes.d.ts +17 -0
- package/dist/inventory/internalTypes.js +2 -0
- package/dist/inventory/internalTypes.js.map +1 -0
- package/dist/inventory/internalUtils.d.ts +10 -0
- package/dist/inventory/internalUtils.js +68 -0
- package/dist/inventory/internalUtils.js.map +1 -0
- package/dist/inventory/listInventoryView.d.ts +23 -0
- package/dist/inventory/listInventoryView.js +22 -0
- package/dist/inventory/listInventoryView.js.map +1 -0
- package/dist/inventory/loadInventory.d.ts +4 -0
- package/dist/inventory/loadInventory.js +87 -0
- package/dist/inventory/loadInventory.js.map +1 -0
- package/dist/inventory/normalize.d.ts +4 -0
- package/dist/inventory/normalize.js +251 -0
- package/dist/inventory/normalize.js.map +1 -0
- package/dist/inventory/parse.d.ts +6 -0
- package/dist/inventory/parse.js +31 -0
- package/dist/inventory/parse.js.map +1 -0
- package/dist/inventory/policy.d.ts +11 -0
- package/dist/inventory/policy.js +27 -0
- package/dist/inventory/policy.js.map +1 -0
- package/dist/inventory/resolveTarget.d.ts +14 -0
- package/dist/inventory/resolveTarget.js +55 -0
- package/dist/inventory/resolveTarget.js.map +1 -0
- package/dist/inventory/types.d.ts +50 -0
- package/dist/inventory/types.js +2 -0
- package/dist/inventory/types.js.map +1 -0
- package/dist/inventory/validateNormalized.d.ts +2 -0
- package/dist/inventory/validateNormalized.js +64 -0
- package/dist/inventory/validateNormalized.js.map +1 -0
- package/dist/inventory/varValidation.d.ts +2 -0
- package/dist/inventory/varValidation.js +60 -0
- package/dist/inventory/varValidation.js.map +1 -0
- package/dist/inventory/writePolicy.d.ts +2 -0
- package/dist/inventory/writePolicy.js +36 -0
- package/dist/inventory/writePolicy.js.map +1 -0
- package/dist/logging/loggingQuery.d.ts +15 -0
- package/dist/logging/loggingQuery.js +38 -0
- package/dist/logging/loggingQuery.js.map +1 -0
- package/dist/logging/showLogging.d.ts +28 -0
- package/dist/logging/showLogging.js +37 -0
- package/dist/logging/showLogging.js.map +1 -0
- package/dist/mcp/createServer.d.ts +3 -0
- package/dist/mcp/createServer.js +82 -0
- package/dist/mcp/createServer.js.map +1 -0
- package/dist/mcp/toolResult.d.ts +7 -0
- package/dist/mcp/toolResult.js +13 -0
- package/dist/mcp/toolResult.js.map +1 -0
- package/dist/mcp/tools/getFacts.d.ts +21 -0
- package/dist/mcp/tools/getFacts.js +17 -0
- package/dist/mcp/tools/getFacts.js.map +1 -0
- package/dist/mcp/tools/getRunningConfig.d.ts +21 -0
- package/dist/mcp/tools/getRunningConfig.js +17 -0
- package/dist/mcp/tools/getRunningConfig.js.map +1 -0
- package/dist/mcp/tools/getServerInfo.d.ts +10 -0
- package/dist/mcp/tools/getServerInfo.js +9 -0
- package/dist/mcp/tools/getServerInfo.js.map +1 -0
- package/dist/mcp/tools/listInventory.d.ts +16 -0
- package/dist/mcp/tools/listInventory.js +15 -0
- package/dist/mcp/tools/listInventory.js.map +1 -0
- package/dist/mcp/tools/probeDevices.d.ts +21 -0
- package/dist/mcp/tools/probeDevices.js +14 -0
- package/dist/mcp/tools/probeDevices.js.map +1 -0
- package/dist/mcp/tools/runShow.d.ts +30 -0
- package/dist/mcp/tools/runShow.js +34 -0
- package/dist/mcp/tools/runShow.js.map +1 -0
- package/dist/mcp/tools/showLogging.d.ts +24 -0
- package/dist/mcp/tools/showLogging.js +20 -0
- package/dist/mcp/tools/showLogging.js.map +1 -0
- package/dist/operations/readExecution.d.ts +57 -0
- package/dist/operations/readExecution.js +132 -0
- package/dist/operations/readExecution.js.map +1 -0
- package/dist/probe/probeDevices.d.ts +24 -0
- package/dist/probe/probeDevices.js +24 -0
- package/dist/probe/probeDevices.js.map +1 -0
- package/dist/serverInfo/buildServerInfo.d.ts +2 -0
- package/dist/serverInfo/buildServerInfo.js +49 -0
- package/dist/serverInfo/buildServerInfo.js.map +1 -0
- package/dist/serverInfo/types.d.ts +46 -0
- package/dist/serverInfo/types.js +2 -0
- package/dist/serverInfo/types.js.map +1 -0
- package/dist/show/runShow.d.ts +29 -0
- package/dist/show/runShow.js +40 -0
- package/dist/show/runShow.js.map +1 -0
- package/dist/utils/json.d.ts +1 -0
- package/dist/utils/json.js +4 -0
- package/dist/utils/json.js.map +1 -0
- package/dist/utils/path.d.ts +2 -0
- package/dist/utils/path.js +14 -0
- package/dist/utils/path.js.map +1 -0
- package/dist/utils/value.d.ts +6 -0
- package/dist/utils/value.js +28 -0
- package/dist/utils/value.js.map +1 -0
- package/docs/CHECKPOINT.md +46 -0
- package/docs/CODE_WALKTHROUGH.md +112 -0
- package/docs/DESIGN.md +56 -0
- package/docs/DEVELOPMENT.md +72 -0
- package/docs/EXAMPLES.md +178 -0
- package/docs/IMPLEMENTATION_PLAN.md +32 -0
- package/docs/QUICKSTART.md +152 -0
- package/example-inventories/canonical-fabric.yaml +45 -0
- package/example-inventories/multi-password.yaml +35 -0
- package/example-inventories/simplified-lab.yaml +33 -0
- package/package.json +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,652 @@
|
|
|
1
|
+
# eos-mcp-server BETA
|
|
2
|
+
|
|
3
|
+
Read-only MCP server for Arista EOS eAPI (JSON-RPC over HTTPS).
|
|
4
|
+
|
|
5
|
+
> **Beta status:** this project is under active development.
|
|
6
|
+
> **Support:** best-effort only. This open source project is not currently supported by Arista TAC.
|
|
7
|
+
|
|
8
|
+
This server provides a set of **read-only** tools. It never exposes configuration-changing operations. The server can:
|
|
9
|
+
|
|
10
|
+
- introspect its own runtime and inventory
|
|
11
|
+
- list inventory hosts/groups
|
|
12
|
+
- probe EOS device readiness
|
|
13
|
+
- run `show` commands
|
|
14
|
+
- retrieve bounded logging output for troubleshooting
|
|
15
|
+
- collect a fixed set of device facts
|
|
16
|
+
- retrieve running configuration
|
|
17
|
+
|
|
18
|
+
> **Security note:** LLMs have occasionally tried to bypass the MCP server and make configuration changes through other means (for example, SSH). As a best practice, use AAA and scope the authentication credentials used by this server to read-only access.
|
|
19
|
+
|
|
20
|
+
## Contents
|
|
21
|
+
|
|
22
|
+
- [What's included](#whats-included)
|
|
23
|
+
- [Requirements](#requirements)
|
|
24
|
+
- [Install and get started](#install-and-get-started)
|
|
25
|
+
- [Server config file](#server-config-file)
|
|
26
|
+
- [Connect to an MCP client](#connect-to-an-mcp-client)
|
|
27
|
+
- [CLI usage](#cli-usage)
|
|
28
|
+
- [MCP tool reference](#mcp-tool-reference)
|
|
29
|
+
- [Inventory formats](#inventory-formats)
|
|
30
|
+
- [Connection and authentication](#connection-and-authentication)
|
|
31
|
+
- [TLS behavior](#tls-behavior)
|
|
32
|
+
- [Common troubleshooting](#common-troubleshooting)
|
|
33
|
+
- [EOS version compatibility](#eos-version-compatibility)
|
|
34
|
+
|
|
35
|
+
## What's included
|
|
36
|
+
|
|
37
|
+
Implemented MCP tools:
|
|
38
|
+
|
|
39
|
+
- `eos_get_server_info`
|
|
40
|
+
- `eos_list_inventory`
|
|
41
|
+
- `eos_probe_devices`
|
|
42
|
+
- `eos_run_show`
|
|
43
|
+
- `eos_show_logging`
|
|
44
|
+
- `eos_get_facts`
|
|
45
|
+
- `eos_get_running_config`
|
|
46
|
+
|
|
47
|
+
Implemented local CLI commands:
|
|
48
|
+
|
|
49
|
+
- `serve`
|
|
50
|
+
- `validate-inventory`
|
|
51
|
+
- `print-server-info`
|
|
52
|
+
- `probe`
|
|
53
|
+
|
|
54
|
+
## Requirements
|
|
55
|
+
|
|
56
|
+
- Node.js 24+
|
|
57
|
+
- Arista EOS devices reachable via eAPI over HTTPS
|
|
58
|
+
- EOS 4.20 or later
|
|
59
|
+
- Inventory in one of the supported YAML formats
|
|
60
|
+
|
|
61
|
+
## Install and get started
|
|
62
|
+
|
|
63
|
+
1. Install the package globally from npm:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm install -g @aristanetworks/eos-mcp-server
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Prereleases are published under the `next` tag (`npm install -g @aristanetworks/eos-mcp-server@next`). Each [GitHub release](https://github.com/aristanetworks/eos-mcp-server/releases) also attaches the package as a `.tgz`, which you can install with `npm install -g ./aristanetworks-eos-mcp-server-<version>.tgz`.
|
|
70
|
+
|
|
71
|
+
2. Confirm that the command is available:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
eos-mcp-server --help
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The global install places `eos-mcp-server` on your `PATH`. To remove it later:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
npm uninstall -g @aristanetworks/eos-mcp-server
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Next, create an inventory, provide the device password, and validate connectivity:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
export EOS_MCP_PASSWORD='replace-with-device-password'
|
|
87
|
+
|
|
88
|
+
eos-mcp-server validate-inventory --inventory inventory.yml
|
|
89
|
+
eos-mcp-server probe --inventory inventory.yml --target leaf1
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
See [Quickstart](docs/QUICKSTART.md) for a complete inventory example and MCP client setup. For building or contributing from source, see the [developer workflow](docs/DEVELOPMENT.md).
|
|
93
|
+
|
|
94
|
+
## Server config file
|
|
95
|
+
|
|
96
|
+
The server needs an inventory to start. At minimum, provide one of:
|
|
97
|
+
|
|
98
|
+
- `--inventory <path>` directly, or
|
|
99
|
+
- `--config <path>` pointing at a YAML config file that itself sets `inventory: <path>`
|
|
100
|
+
|
|
101
|
+
Beyond that minimum, a config file is optional — use one when you want to set additional options such as timeouts, request limits, or a default connection. CLI flags always override config-file values.
|
|
102
|
+
|
|
103
|
+
Example:
|
|
104
|
+
|
|
105
|
+
```yaml
|
|
106
|
+
version: 1
|
|
107
|
+
inventory: ./inventory.yml
|
|
108
|
+
actor: lab-user
|
|
109
|
+
readTimeoutMs: 10000
|
|
110
|
+
overallOperationTimeoutMs: 30000
|
|
111
|
+
deviceConcurrency: 5
|
|
112
|
+
maxReadTargets: 50
|
|
113
|
+
maxShowCommandsPerRequest: 5
|
|
114
|
+
maxLoggingMessagesPerRequest: 1000
|
|
115
|
+
maxResponseSizeBytes: 1048576
|
|
116
|
+
eapiVersion: latest
|
|
117
|
+
secretEnvPrefixes:
|
|
118
|
+
- EOS_MCP_
|
|
119
|
+
defaultConnection:
|
|
120
|
+
ansibleUser: admin
|
|
121
|
+
mcpPasswordEnv: EOS_MCP_PASSWORD
|
|
122
|
+
mcpValidateCerts: false
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Supported config fields:
|
|
126
|
+
|
|
127
|
+
- `inventory`
|
|
128
|
+
- `actor`
|
|
129
|
+
- `caFile`
|
|
130
|
+
- `readTimeoutMs`
|
|
131
|
+
- `overallOperationTimeoutMs`
|
|
132
|
+
- `deviceConcurrency`
|
|
133
|
+
- `maxReadTargets`
|
|
134
|
+
- `maxShowCommandsPerRequest`
|
|
135
|
+
- `maxLoggingMessagesPerRequest`
|
|
136
|
+
- `maxResponseSizeBytes`
|
|
137
|
+
- `eapiVersion`
|
|
138
|
+
- `secretEnvPrefixes`
|
|
139
|
+
- `defaultConnection.ansibleUser`
|
|
140
|
+
- `defaultConnection.ansibleHttpapiPort`
|
|
141
|
+
- `defaultConnection.mcpValidateCerts`
|
|
142
|
+
- `defaultConnection.mcpPasswordEnv`
|
|
143
|
+
|
|
144
|
+
`readTimeoutMs` applies to each device eAPI request. `overallOperationTimeoutMs`, when set, bounds the whole tool call and aborts in-flight device requests once the limit is reached. `maxLoggingMessagesPerRequest` caps `eos_show_logging.message_count` and defaults to 1000. `maxResponseSizeBytes` limits both the buffered HTTP response from each device and the final serialized read-tool result. `eapiVersion` selects the eAPI JSON output schema sent as the `runCmds` `version` parameter: `latest` (the default) returns the current schema for each command, and `1` pins the original schema for consumers that depend on it. It only affects JSON output, so `eos_get_running_config` and `eos_show_logging` are unchanged.
|
|
145
|
+
|
|
146
|
+
`defaultConnection.mcpPasswordEnv` is a fallback password source. A host or inherited inventory value for `mcp_password_env` or `ansible_password` overrides it. Setting both `mcp_password_env` and `ansible_password` for the same host remains invalid.
|
|
147
|
+
|
|
148
|
+
## Connect to an MCP client
|
|
149
|
+
|
|
150
|
+
These examples assume you've already installed `eos-mcp-server` per [Install and get started](#install-and-get-started) above, and have an inventory file (and optionally a [server config file](#server-config-file)) ready.
|
|
151
|
+
|
|
152
|
+
### Generic stdio example
|
|
153
|
+
|
|
154
|
+
If `eos-mcp-server` is installed on your `PATH`, point it at just an inventory file:
|
|
155
|
+
|
|
156
|
+
```json
|
|
157
|
+
{
|
|
158
|
+
"mcpServers": {
|
|
159
|
+
"eos": {
|
|
160
|
+
"command": "eos-mcp-server",
|
|
161
|
+
"args": ["serve", "--inventory", "/absolute/path/to/inventory.yml"]
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Or use a [server config file](#server-config-file) if you want to set additional options:
|
|
168
|
+
|
|
169
|
+
```json
|
|
170
|
+
{
|
|
171
|
+
"mcpServers": {
|
|
172
|
+
"eos": {
|
|
173
|
+
"command": "eos-mcp-server",
|
|
174
|
+
"args": ["serve", "--config", "/absolute/path/to/eos-mcp-server.yml"]
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
If you built the project locally instead of installing the package, replace `"command": "eos-mcp-server"` with `"command": "node"` and put `/absolute/path/to/eos-mcp-server/dist/index.js` first in `args`.
|
|
181
|
+
|
|
182
|
+
### Claude Code
|
|
183
|
+
|
|
184
|
+
With just an inventory file:
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
claude mcp add eos -- eos-mcp-server serve --inventory /absolute/path/to/inventory.yml
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Or with a [server config file](#server-config-file) for additional options:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
claude mcp add eos -- eos-mcp-server serve --config /absolute/path/to/eos-mcp-server.yml
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Add `-s user` before `eos` in either command to make the server available across all your projects instead of just the current one:
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
claude mcp add -s user eos -- eos-mcp-server serve --inventory /absolute/path/to/inventory.yml
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Codex
|
|
203
|
+
|
|
204
|
+
Add the server to `.codex/config.toml` in a trusted project, or to
|
|
205
|
+
`~/.codex/config.toml` for all projects.
|
|
206
|
+
|
|
207
|
+
With just an inventory file:
|
|
208
|
+
|
|
209
|
+
```toml
|
|
210
|
+
[mcp_servers.eos]
|
|
211
|
+
command = "eos-mcp-server"
|
|
212
|
+
args = ["serve", "--inventory", "/absolute/path/to/inventory.yml"]
|
|
213
|
+
env_vars = ["EOS_MCP_PASSWORD"]
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Or with a [server config file](#server-config-file) for additional options:
|
|
217
|
+
|
|
218
|
+
```toml
|
|
219
|
+
[mcp_servers.eos]
|
|
220
|
+
command = "eos-mcp-server"
|
|
221
|
+
args = ["serve", "--config", "/absolute/path/to/eos-mcp-server.yml"]
|
|
222
|
+
env_vars = ["EOS_MCP_PASSWORD"]
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
`serve` is optional because it is the default command, but is shown explicitly
|
|
226
|
+
here for clarity. You can also add the server with:
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
codex mcp add eos -- eos-mcp-server serve --inventory /absolute/path/to/inventory.yml
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Then add `env_vars = ["EOS_MCP_PASSWORD"]` to the generated
|
|
233
|
+
`[mcp_servers.eos]` table.
|
|
234
|
+
|
|
235
|
+
### Passing secrets to the MCP server
|
|
236
|
+
|
|
237
|
+
Prefer exporting secrets in the environment that launches the MCP client:
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
export EOS_MCP_PASSWORD='super-secret'
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
For Codex, `env_vars = ["EOS_MCP_PASSWORD"]` forwards that exported variable to
|
|
244
|
+
the server. Other MCP clients may support per-server `env` blocks. Avoid
|
|
245
|
+
committing secret values to client config files when possible.
|
|
246
|
+
|
|
247
|
+
## Inventory formats
|
|
248
|
+
|
|
249
|
+
The server supports exactly one inventory file loaded at startup. The inventory is not watched for changes — to pick up inventory edits, restart the server. Most MCP clients will do this automatically when you restart the client or re-launch the MCP connection.
|
|
250
|
+
|
|
251
|
+
Supported formats:
|
|
252
|
+
|
|
253
|
+
- canonical Ansible-style YAML
|
|
254
|
+
- simplified YAML
|
|
255
|
+
|
|
256
|
+
Canonical inventories must have `all` as the only top-level key. Simplified inventories may use only `version`, `vars`, `hosts`, and `groups` at the top level. Unknown structural keys are rejected; unknown keys inside `vars` remain allowed.
|
|
257
|
+
|
|
258
|
+
### Canonical Ansible-style example
|
|
259
|
+
|
|
260
|
+
```yaml
|
|
261
|
+
all:
|
|
262
|
+
children:
|
|
263
|
+
eos:
|
|
264
|
+
vars:
|
|
265
|
+
ansible_user: admin
|
|
266
|
+
ansible_network_os: eos
|
|
267
|
+
mcp_password_env: EOS_MCP_PASSWORD
|
|
268
|
+
hosts:
|
|
269
|
+
leaf1:
|
|
270
|
+
ansible_host: 192.0.2.11
|
|
271
|
+
leaf2:
|
|
272
|
+
ansible_host: 192.0.2.12
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Simplified YAML example
|
|
276
|
+
|
|
277
|
+
```yaml
|
|
278
|
+
version: 1
|
|
279
|
+
vars:
|
|
280
|
+
ansible_user: admin
|
|
281
|
+
mcp_password_env: EOS_MCP_PASSWORD
|
|
282
|
+
|
|
283
|
+
hosts:
|
|
284
|
+
leaf1:
|
|
285
|
+
ansible_host: 192.0.2.11
|
|
286
|
+
ansible_network_os: eos
|
|
287
|
+
leaf2:
|
|
288
|
+
ansible_host: 192.0.2.12
|
|
289
|
+
ansible_network_os: eos
|
|
290
|
+
|
|
291
|
+
groups:
|
|
292
|
+
leafs:
|
|
293
|
+
hosts: [leaf1, leaf2]
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
For an inventory where devices do not share a password, see
|
|
297
|
+
[`example-inventories/multi-password.yaml`](example-inventories/multi-password.yaml).
|
|
298
|
+
Each host sets its own `mcp_password_env` reference, so the actual passwords
|
|
299
|
+
remain in the environment rather than in the inventory file. For example:
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
export EOS_MCP_SPINE1_PASSWORD='spine1-password'
|
|
303
|
+
export EOS_MCP_SPINE2_PASSWORD='spine2-password'
|
|
304
|
+
export EOS_MCP_LEAF1_PASSWORD='leaf1-password'
|
|
305
|
+
export EOS_MCP_LEAF2_PASSWORD='leaf2-password'
|
|
306
|
+
|
|
307
|
+
eos-mcp-server validate-inventory \
|
|
308
|
+
--inventory example-inventories/multi-password.yaml
|
|
309
|
+
eos-mcp-server serve --inventory example-inventories/multi-password.yaml
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
The password environment variable name is resolved independently for each
|
|
313
|
+
host. Host-level values override inherited group or global values, so devices
|
|
314
|
+
can be queried together through the `FABRIC`, `SPINES`, or `LEAFS` targets while
|
|
315
|
+
still using their individual credentials.
|
|
316
|
+
|
|
317
|
+
## Important inventory rules
|
|
318
|
+
|
|
319
|
+
- Targets must be **inventory host or group names**, not IP addresses.
|
|
320
|
+
- Host/group names must match `^[A-Za-z0-9_.-]+$`.
|
|
321
|
+
- Duplicate YAML keys are rejected.
|
|
322
|
+
- The simplified schema reserves `all`; do not define `groups.all` there.
|
|
323
|
+
- Group graphs must be acyclic.
|
|
324
|
+
- EOS eligibility comes from either:
|
|
325
|
+
- `ansible_network_os: eos`
|
|
326
|
+
- `mcp_platform: arista_eos`
|
|
327
|
+
- `mcp_read_allowed` defaults to `true` for eligible EOS hosts. Set it to `false` — inherited like any other variable — to explicitly deny read access to a host or group.
|
|
328
|
+
- Read operations fail closed if the resolved target contains ineligible or read-denied hosts.
|
|
329
|
+
|
|
330
|
+
## Connection and authentication
|
|
331
|
+
|
|
332
|
+
### Supported connection fields
|
|
333
|
+
|
|
334
|
+
The read path currently uses these effective fields:
|
|
335
|
+
|
|
336
|
+
- `ansible_host` - device hostname/IP for HTTPS connection
|
|
337
|
+
- `ansible_httpapi_port` - optional eAPI port, default `443`
|
|
338
|
+
- `ansible_user` - username
|
|
339
|
+
- `mcp_password_env` - preferred password source, treated as an **environment variable name**
|
|
340
|
+
- `ansible_password` - literal password source
|
|
341
|
+
- `mcp_validate_certs` - optional boolean to disable TLS validation for a lab target; `ansible_httpapi_validate_certs` is also accepted as a fallback
|
|
342
|
+
|
|
343
|
+
### Password source rules
|
|
344
|
+
|
|
345
|
+
Exactly one password source must resolve per EOS host:
|
|
346
|
+
|
|
347
|
+
- `mcp_password_env`
|
|
348
|
+
- `ansible_password`
|
|
349
|
+
|
|
350
|
+
Do **not** set both.
|
|
351
|
+
|
|
352
|
+
If you use `mcp_password_env`, the value must be the **name of an environment variable**, not the password itself.
|
|
353
|
+
|
|
354
|
+
Correct:
|
|
355
|
+
|
|
356
|
+
```yaml
|
|
357
|
+
mcp_password_env: EOS_MCP_PASSWORD
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
Incorrect:
|
|
361
|
+
|
|
362
|
+
```yaml
|
|
363
|
+
mcp_password_env: admin
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
The default allowed env var prefix is `EOS_MCP_`, so names like `EOS_MCP_PASSWORD` work by default.
|
|
367
|
+
|
|
368
|
+
Example:
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
export EOS_MCP_PASSWORD='replace-with-device-password'
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
## TLS behavior
|
|
375
|
+
|
|
376
|
+
- HTTPS only
|
|
377
|
+
- certificate validation is **on by default**
|
|
378
|
+
- optional custom CA bundle via config file `caFile`
|
|
379
|
+
- per-target or inherited inventory override via `mcp_validate_certs: false` (or `ansible_httpapi_validate_certs: false`)
|
|
380
|
+
|
|
381
|
+
There is currently **no CLI `--insecure` flag**.
|
|
382
|
+
|
|
383
|
+
### Disable cert validation for a lab inventory
|
|
384
|
+
|
|
385
|
+
```yaml
|
|
386
|
+
all:
|
|
387
|
+
children:
|
|
388
|
+
eos:
|
|
389
|
+
vars:
|
|
390
|
+
ansible_user: admin
|
|
391
|
+
ansible_network_os: eos
|
|
392
|
+
mcp_password_env: EOS_MCP_PASSWORD
|
|
393
|
+
mcp_validate_certs: false
|
|
394
|
+
hosts:
|
|
395
|
+
leaf1:
|
|
396
|
+
ansible_host: 192.0.2.11
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### Prefer a CA bundle when possible
|
|
400
|
+
|
|
401
|
+
Server config:
|
|
402
|
+
|
|
403
|
+
```yaml
|
|
404
|
+
inventory: inventory.yml
|
|
405
|
+
caFile: /path/to/ca.pem
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
## CLI usage
|
|
409
|
+
|
|
410
|
+
If no subcommand is provided, the CLI defaults to `serve`.
|
|
411
|
+
|
|
412
|
+
### `serve`
|
|
413
|
+
|
|
414
|
+
Start the MCP server over stdio.
|
|
415
|
+
|
|
416
|
+
```bash
|
|
417
|
+
eos-mcp-server serve --inventory inventory.yml
|
|
418
|
+
eos-mcp-server serve --config eos-mcp-server.yml
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
On startup, `serve` loads the inventory and validates startup connection requirements for EOS-eligible hosts.
|
|
422
|
+
|
|
423
|
+
### `validate-inventory`
|
|
424
|
+
|
|
425
|
+
Validate the inventory file.
|
|
426
|
+
|
|
427
|
+
Default behavior performs:
|
|
428
|
+
|
|
429
|
+
- inventory parsing and structural validation
|
|
430
|
+
- effective inventory validation
|
|
431
|
+
- startup-style connection validation for EOS-eligible hosts using the loaded config/default connection settings
|
|
432
|
+
|
|
433
|
+
Use `--inventory-only` to skip the startup connection checks.
|
|
434
|
+
|
|
435
|
+
### `print-server-info`
|
|
436
|
+
|
|
437
|
+
Print the server's sanitized runtime/config summary.
|
|
438
|
+
|
|
439
|
+
```bash
|
|
440
|
+
eos-mcp-server print-server-info --inventory inventory.yml
|
|
441
|
+
eos-mcp-server print-server-info --config eos-mcp-server.yml --json
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
### `probe`
|
|
445
|
+
|
|
446
|
+
Probe a host or group target using the same logic as the MCP tool.
|
|
447
|
+
|
|
448
|
+
```bash
|
|
449
|
+
eos-mcp-server probe --inventory inventory.yml --target leaf1
|
|
450
|
+
eos-mcp-server probe --inventory inventory.yml --target leafs --json
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
Human-readable example output:
|
|
454
|
+
|
|
455
|
+
```text
|
|
456
|
+
Probe target: leaf1
|
|
457
|
+
Devices: 1/1 succeeded
|
|
458
|
+
- leaf1: success
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
## MCP tool reference
|
|
462
|
+
|
|
463
|
+
### `eos_get_server_info`
|
|
464
|
+
|
|
465
|
+
Returns a sanitized summary of server runtime, capabilities, limits, TLS/config posture, and inventory summary.
|
|
466
|
+
|
|
467
|
+
Input:
|
|
468
|
+
|
|
469
|
+
```json
|
|
470
|
+
{}
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
### `eos_list_inventory`
|
|
474
|
+
|
|
475
|
+
Returns a sanitized view of the loaded inventory.
|
|
476
|
+
|
|
477
|
+
Input:
|
|
478
|
+
|
|
479
|
+
```json
|
|
480
|
+
{
|
|
481
|
+
"include_ineligible": false
|
|
482
|
+
}
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
### `eos_probe_devices`
|
|
486
|
+
|
|
487
|
+
Checks operational readiness for a host or group by contacting devices and running a harmless command.
|
|
488
|
+
|
|
489
|
+
Input:
|
|
490
|
+
|
|
491
|
+
```json
|
|
492
|
+
{
|
|
493
|
+
"target": "leaf1",
|
|
494
|
+
"include_raw": false
|
|
495
|
+
}
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
### `eos_run_show`
|
|
499
|
+
|
|
500
|
+
Runs one or more `show` commands.
|
|
501
|
+
|
|
502
|
+
Rules:
|
|
503
|
+
|
|
504
|
+
- exactly one of `command` or `commands`
|
|
505
|
+
- every command is trimmed, must be a single line, and must be `show` or begin with `show`
|
|
506
|
+
- commands with CLI output modifiers or shell metacharacters such as `|`, `>`, `<`, `;`, `&`, backticks, or `$` are rejected before device contact
|
|
507
|
+
- `output_format` is one of `auto`, `json`, `text`
|
|
508
|
+
- `include_raw` optionally attaches each command's raw eAPI result entry as `raw_entry` inside `command_results`
|
|
509
|
+
|
|
510
|
+
Input examples:
|
|
511
|
+
|
|
512
|
+
```json
|
|
513
|
+
{
|
|
514
|
+
"target": "leaf1",
|
|
515
|
+
"command": "show version",
|
|
516
|
+
"output_format": "auto"
|
|
517
|
+
}
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
```json
|
|
521
|
+
{
|
|
522
|
+
"target": "leafs",
|
|
523
|
+
"commands": ["show version", "show interfaces status"],
|
|
524
|
+
"output_format": "json",
|
|
525
|
+
"include_raw": false
|
|
526
|
+
}
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
### `eos_show_logging`
|
|
530
|
+
|
|
531
|
+
Retrieves bounded EOS logging output for a host or group target. The tool always uses text output and generates `show logging threshold <minimum_severity> <message_count>`. `minimum_severity` is a threshold, so `warnings` includes warning and more urgent log messages. Defaults are `minimum_severity: "warnings"` and `message_count: 100`; `message_count` is capped by `maxLoggingMessagesPerRequest`.
|
|
532
|
+
|
|
533
|
+
Input example:
|
|
534
|
+
|
|
535
|
+
```json
|
|
536
|
+
{
|
|
537
|
+
"target": "leaf1",
|
|
538
|
+
"minimum_severity": "warnings",
|
|
539
|
+
"message_count": 100
|
|
540
|
+
}
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
Allowed severities are `emergencies`, `alerts`, `critical`, `errors`, `warnings`, `notifications`, `informational`, and `debugging`.
|
|
544
|
+
|
|
545
|
+
### `eos_get_facts`
|
|
546
|
+
|
|
547
|
+
Collects a small, fixed core facts set from `show version`.
|
|
548
|
+
|
|
549
|
+
Input:
|
|
550
|
+
|
|
551
|
+
```json
|
|
552
|
+
{
|
|
553
|
+
"target": "leaf1",
|
|
554
|
+
"include_raw": false
|
|
555
|
+
}
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
### `eos_get_running_config`
|
|
559
|
+
|
|
560
|
+
Returns running config text for a host target, or for a group target when `section` is provided. Automatically enters enable mode via eAPI since `show running-config` requires privileged access. `section` is trimmed and must be a single-line EOS section selector without CLI output modifiers or shell metacharacters.
|
|
561
|
+
|
|
562
|
+
Input examples:
|
|
563
|
+
|
|
564
|
+
```json
|
|
565
|
+
{
|
|
566
|
+
"target": "leaf1"
|
|
567
|
+
}
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
```json
|
|
571
|
+
{
|
|
572
|
+
"target": "leafs",
|
|
573
|
+
"section": "router bgp"
|
|
574
|
+
}
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
## Common troubleshooting
|
|
578
|
+
|
|
579
|
+
### `Password env var ... does not match any allowed prefix`
|
|
580
|
+
|
|
581
|
+
`mcp_password_env` must contain an **environment variable name** like `EOS_MCP_PASSWORD`, not the password itself.
|
|
582
|
+
|
|
583
|
+
### `Password env var ... is not set`
|
|
584
|
+
|
|
585
|
+
Export the referenced environment variable before launching `probe` or `serve`.
|
|
586
|
+
|
|
587
|
+
### Certificate validation failure
|
|
588
|
+
|
|
589
|
+
Use one of:
|
|
590
|
+
|
|
591
|
+
- `caFile` in the server config to trust your lab CA
|
|
592
|
+
- `mcp_validate_certs: false` (or `ansible_httpapi_validate_certs: false`) in inventory for a lab/dev target
|
|
593
|
+
|
|
594
|
+
There is no CLI TLS-disable flag today.
|
|
595
|
+
|
|
596
|
+
### `Unknown inventory target ...`
|
|
597
|
+
|
|
598
|
+
Tool and CLI targets must be inventory names, not `ansible_host` IPs.
|
|
599
|
+
|
|
600
|
+
### Group running-config request failed without `section`
|
|
601
|
+
|
|
602
|
+
For `eos_get_running_config`, group targets require a `section` value.
|
|
603
|
+
|
|
604
|
+
### Command or section rejected as invalid
|
|
605
|
+
|
|
606
|
+
`eos_run_show` accepts only single-line `show` commands. `eos_get_running_config.section` must also be a single-line selector. Newlines, other control characters, CLI output modifiers, and shell metacharacters are rejected before any device contact.
|
|
607
|
+
|
|
608
|
+
### Response too large
|
|
609
|
+
|
|
610
|
+
Read tools are bounded by `maxResponseSizeBytes`. The server rejects oversized device HTTP responses before buffering them fully, and also rejects oversized aggregate tool results with narrowing guidance. For `eos_show_logging`, reduce `message_count`, target fewer devices, or raise `minimum_severity`.
|
|
611
|
+
|
|
612
|
+
### Policy denied when probing a device
|
|
613
|
+
|
|
614
|
+
Example:
|
|
615
|
+
|
|
616
|
+
```
|
|
617
|
+
eos-mcp-server probe --inventory clab/clab-testlab/ansible-inventory.yml --target clab-testlab-node1-1
|
|
618
|
+
Policy denied: target clab-testlab-node1-1 includes host(s) not permitted for read operations: clab-testlab-node1-1
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
This means the target resolved to at least one host that is either not marked as EOS eligible (`ansible_network_os: eos` or `mcp_platform: arista_eos`) or has `mcp_read_allowed: false` set.
|
|
622
|
+
|
|
623
|
+
## EOS version compatibility
|
|
624
|
+
|
|
625
|
+
The read-path tools have been validated against EOS 4.34.3M. The minimum supported EOS version for read operations is 4.20, which is when eAPI JSON-RPC became stable and `show` commands reliably produce structured JSON output.
|
|
626
|
+
|
|
627
|
+
## Design notes
|
|
628
|
+
|
|
629
|
+
- inventory is the trust boundary
|
|
630
|
+
- reads are fail-closed on ineligible or denied targets
|
|
631
|
+
- the server exposes only documented read-only operations
|
|
632
|
+
|
|
633
|
+
## Project docs
|
|
634
|
+
|
|
635
|
+
Additional design and planning docs in the `docs/` directory:
|
|
636
|
+
|
|
637
|
+
- `docs/design-overview.md` — design overview for evaluators
|
|
638
|
+
- `docs/DESIGN.md` — detailed design specification
|
|
639
|
+
- `docs/IMPLEMENTATION_PLAN.md` — implemented scope and maintenance priorities
|
|
640
|
+
- `docs/CHECKPOINT.md` — current implementation status
|
|
641
|
+
- `docs/CODE_WALKTHROUGH.md` — source layout and module guide
|
|
642
|
+
- `docs/QUICKSTART.md` — quick start tutorial
|
|
643
|
+
- `docs/EXAMPLES.md` — inventory and usage examples
|
|
644
|
+
|
|
645
|
+
## License
|
|
646
|
+
|
|
647
|
+
Copyright 2026 Arista Networks, Inc.
|
|
648
|
+
|
|
649
|
+
This project is licensed under the [Apache License, Version 2.0](LICENSE).
|
|
650
|
+
Apache-2.0 applies to each released version of this repository. Arista may
|
|
651
|
+
offer later versions under additional or different terms, but cannot revoke
|
|
652
|
+
the Apache-2.0 rights granted for versions already released under it.
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type CommandName = "serve" | "validate-inventory" | "print-server-info" | "probe";
|
|
2
|
+
export interface CliOptions {
|
|
3
|
+
command: CommandName;
|
|
4
|
+
explicitCommand?: boolean;
|
|
5
|
+
help?: boolean;
|
|
6
|
+
version?: boolean;
|
|
7
|
+
configPath?: string;
|
|
8
|
+
inventoryPath?: string;
|
|
9
|
+
actor?: string;
|
|
10
|
+
json?: boolean;
|
|
11
|
+
inventoryOnly?: boolean;
|
|
12
|
+
target?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function parseCliArgs(argv: string[]): CliOptions;
|
|
15
|
+
export declare function printHelp(cli: CliOptions): void;
|
|
16
|
+
export declare function printVersion(): void;
|