@aristanetworks/eos-mcp-server 0.8.0-beta → 0.9.0-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 +13 -0
- package/README.md +19 -42
- package/dist/cli.d.ts +1 -4
- package/dist/cli.js +4 -63
- package/dist/cli.js.map +1 -1
- package/dist/commands/probe.js +2 -1
- package/dist/commands/probe.js.map +1 -1
- package/dist/config/diagnostics.d.ts +15 -5
- package/dist/config/diagnostics.js +8 -3
- package/dist/config/diagnostics.js.map +1 -1
- package/dist/config/loadConfig.js +2 -5
- package/dist/config/loadConfig.js.map +1 -1
- package/dist/config/schema.d.ts +123 -15
- package/dist/config/schema.js +14 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/connection/eosDeviceReader.d.ts +6 -1
- package/dist/connection/eosDeviceReader.js +14 -3
- package/dist/connection/eosDeviceReader.js.map +1 -1
- package/dist/diagnostics/eapiRunner.js +7 -1
- package/dist/diagnostics/eapiRunner.js.map +1 -1
- package/dist/diagnostics/executor.d.ts +7 -4
- package/dist/diagnostics/executor.js +16 -14
- package/dist/diagnostics/executor.js.map +1 -1
- package/dist/diagnostics/types.d.ts +22 -6
- package/dist/eapi/client.js +5 -4
- package/dist/eapi/client.js.map +1 -1
- package/dist/eapi/types.d.ts +3 -0
- package/dist/eapi/types.js.map +1 -1
- package/dist/index.js +0 -10
- package/dist/index.js.map +1 -1
- package/dist/mcp/createServer.js +21 -21
- package/dist/mcp/createServer.js.map +1 -1
- package/dist/mcp/tools/ping.d.ts +2 -9
- package/dist/mcp/tools/ping.js +13 -26
- package/dist/mcp/tools/ping.js.map +1 -1
- package/dist/operations/eapiSlots.d.ts +68 -0
- package/dist/operations/eapiSlots.js +237 -0
- package/dist/operations/eapiSlots.js.map +1 -0
- package/dist/operations/readExecution.js +1 -1
- package/dist/operations/readExecution.js.map +1 -1
- package/dist/serverInfo/buildServerInfo.js +4 -1
- package/dist/serverInfo/buildServerInfo.js.map +1 -1
- package/dist/serverInfo/types.d.ts +3 -0
- package/docs/CHECKPOINT.md +3 -6
- package/docs/CODE_WALKTHROUGH.md +6 -11
- package/docs/DEMO_SKILLS_YOUTUBE.md +346 -0
- package/docs/DESIGN.md +4 -4
- package/docs/DIAGNOSTICS.md +26 -74
- package/docs/IMPLEMENTATION_PLAN.md +2 -2
- package/docs/adr/0002-fail-closed-diagnostic-reservations.md +2 -0
- package/docs/adr/0003-durable-diagnostic-ledger.md +2 -0
- package/docs/adr/0004-offline-operator-attested-release.md +2 -0
- package/docs/adr/0005-multi-destination-ping.md +5 -1
- package/docs/adr/0006-in-memory-timed-diagnostic-capacity.md +23 -0
- package/docs/adr/0007-per-device-diagnostic-concurrency.md +16 -0
- package/docs/adr/0008-read-only-tool-annotations.md +16 -0
- package/docs/adr/0009-shared-per-device-eapi-slots.md +40 -0
- package/docs/research/eos-diagnostic-lifecycle.md +2 -0
- package/docs/research/eos-linter-integration.md +70 -0
- package/package.json +1 -1
- package/dist/commands/inspectDiagnostics.d.ts +0 -3
- package/dist/commands/inspectDiagnostics.js +0 -35
- package/dist/commands/inspectDiagnostics.js.map +0 -1
- package/dist/commands/releaseDiagnostics.d.ts +0 -9
- package/dist/commands/releaseDiagnostics.js +0 -87
- package/dist/commands/releaseDiagnostics.js.map +0 -1
- package/dist/diagnostics/concurrency.d.ts +0 -33
- package/dist/diagnostics/concurrency.js +0 -157
- package/dist/diagnostics/concurrency.js.map +0 -1
- package/dist/diagnostics/journal.d.ts +0 -14
- package/dist/diagnostics/journal.js +0 -317
- package/dist/diagnostics/journal.js.map +0 -1
- package/dist/diagnostics/journalTypes.d.ts +0 -8
- package/dist/diagnostics/journalTypes.js +0 -2
- package/dist/diagnostics/journalTypes.js.map +0 -1
- package/dist/diagnostics/releaseEvidence.d.ts +0 -502
- package/dist/diagnostics/releaseEvidence.js +0 -115
- package/dist/diagnostics/releaseEvidence.js.map +0 -1
- package/dist/diagnostics/reservationSchema.d.ts +0 -49
- package/dist/diagnostics/reservationSchema.js +0 -18
- package/dist/diagnostics/reservationSchema.js.map +0 -1
- package/dist/diagnostics/statePath.d.ts +0 -4
- package/dist/diagnostics/statePath.js +0 -25
- package/dist/diagnostics/statePath.js.map +0 -1
- package/dist/utils/privateFile.d.ts +0 -3
- package/dist/utils/privateFile.js +0 -7
- package/dist/utils/privateFile.js.map +0 -1
- package/docs/examples/diagnostic-release-evidence.template.json +0 -26
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
# Five-minute demo: EOS MCP Server + Skills
|
|
2
|
+
|
|
3
|
+
**Suggested YouTube title:** Arista EOS + AI Skills: Get Started with Claude Code and Codex
|
|
4
|
+
|
|
5
|
+
**Audience:** Network engineers who are new to AI skills. No MCP or skills experience assumed; basic familiarity with switches and BGP helps.
|
|
6
|
+
|
|
7
|
+
**Format:** Screen recording with voiceover. Show installation for both clients, then run BGP health in Claude Code and interface health in Codex. Aim for five minutes after trimming downloads and tool waits. The server connection is prepared before recording; the complete setup is included below for the video description or companion notes.
|
|
8
|
+
|
|
9
|
+
**Recording environment:** Use `example-codex/eos-mcp-server-config.yml` for both clients. It selects `clab/ansible-inventory.yml` for the containerlab topology in `clab/testlab.clab.yaml`: eight cEOS nodes, with two spines and six leaves. This demonstration focuses on BGP and virtual link state; CRC errors and physical optics diagnostics are not demonstration goals.
|
|
10
|
+
|
|
11
|
+
Only text marked **Say** is narration. **Screen** and **Presenter notes** are production directions. Results must come from the recording lab; the script does not assume a particular fault or invent output.
|
|
12
|
+
|
|
13
|
+
## Recording script
|
|
14
|
+
|
|
15
|
+
### 0:00–0:20 — Hook
|
|
16
|
+
|
|
17
|
+
**Screen:** Start with a readable BGP report from a rehearsed lab run, then show the two client terminals labeled “Claude Code” and “Codex.”
|
|
18
|
+
|
|
19
|
+
**Say:**
|
|
20
|
+
|
|
21
|
+
> What if you could ask your AI assistant to check BGP or verify your lab links, using a runbook you can actually read?
|
|
22
|
+
>
|
|
23
|
+
> In this video, we'll install skills for the EOS MCP server in both Claude Code and Codex, then try two everyday network checks.
|
|
24
|
+
|
|
25
|
+
### 0:20–0:55 — What is a skill?
|
|
26
|
+
|
|
27
|
+
**Screen:** Open `skills/check-bgp-health/SKILL.md`. Highlight its name, description, commands, and report format. Use this simple overlay:
|
|
28
|
+
|
|
29
|
+
```text
|
|
30
|
+
You ask a question
|
|
31
|
+
↓
|
|
32
|
+
AI assistant follows a skill (the runbook)
|
|
33
|
+
↓
|
|
34
|
+
EOS MCP server provides tools
|
|
35
|
+
↓
|
|
36
|
+
Arista EOS devices return live data through eAPI
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Say:**
|
|
40
|
+
|
|
41
|
+
> A skill is a reusable set of instructions for an AI assistant. Think of it as a runbook: what to check, which commands to use, what to investigate next, and how to report the findings.
|
|
42
|
+
>
|
|
43
|
+
> The MCP server provides access to device data. The skill provides the procedure for using that data.
|
|
44
|
+
>
|
|
45
|
+
> This BGP skill is a Markdown file. You can inspect its checks and reporting instructions before using it. These EOS workflows are read-only.
|
|
46
|
+
|
|
47
|
+
### 0:55–1:15 — Introduce the lab
|
|
48
|
+
|
|
49
|
+
**Screen:** Show `example-codex/eos-mcp-server-config.yml`, then the `arista_ceos` group in `clab/ansible-inventory.yml` and the topology in `clab/testlab.clab.yaml`. Briefly show `eos` connected in each client's `/mcp` view. Prepare those views in advance.
|
|
50
|
+
|
|
51
|
+
**Say:**
|
|
52
|
+
|
|
53
|
+
> Both clients use the example-codex server config, pointing to our containerlab inventory. We have eight cEOS switches: two spines and six leaves, in the “arista_ceos” group.
|
|
54
|
+
>
|
|
55
|
+
> These are containers, so we'll check BGP and virtual links. The inventory defines our targets.
|
|
56
|
+
|
|
57
|
+
### 1:15–2:05 — Install skills in both clients
|
|
58
|
+
|
|
59
|
+
**Screen:** Show the clone step as a command card for viewers, then run the remaining commands from the existing recording checkout at `/home/fred/aristanetworks/eos-mcp-server`. The local containerlab is already prepared there.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
git clone https://github.com/aristanetworks/eos-mcp-server.git
|
|
63
|
+
cd eos-mcp-server
|
|
64
|
+
|
|
65
|
+
mkdir -p .claude/skills .agents/skills
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# Claude Code
|
|
70
|
+
ln -s "$PWD/skills/check-bgp-health" .claude/skills/
|
|
71
|
+
ln -s "$PWD/skills/check-interface-health" .claude/skills/
|
|
72
|
+
ln -s "$PWD/skills/check-route-health" .claude/skills/
|
|
73
|
+
|
|
74
|
+
# Codex
|
|
75
|
+
ln -s "$PWD/skills/check-bgp-health" .agents/skills/
|
|
76
|
+
ln -s "$PWD/skills/check-interface-health" .agents/skills/
|
|
77
|
+
ln -s "$PWD/skills/check-route-health" .agents/skills/
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Say:**
|
|
81
|
+
|
|
82
|
+
> The skills live in the GitHub repository and are separate from the server's npm package. First, clone the repository.
|
|
83
|
+
>
|
|
84
|
+
> Claude Code looks in dot-claude slash skills. Codex looks in dot-agents slash skills. We create both folders.
|
|
85
|
+
>
|
|
86
|
+
> We're installing three workflows: BGP health, interface health, and route health. Each command links one skill folder into one client. Three for Claude Code, then the same three for Codex.
|
|
87
|
+
>
|
|
88
|
+
> Both clients now point at the same skill folders in this project.
|
|
89
|
+
>
|
|
90
|
+
> Keep the clone in place because the links point to it. Now open a fresh session in each client. In Claude Code, type slash to find a skill. In Codex, use slash-skills or type a dollar sign.
|
|
91
|
+
|
|
92
|
+
**Presenter notes:** Show each selector briefly. These are project-level installations; launch both clients in the project where you installed the links. The automated recording uses an isolated project under `.local-artifacts/eos-skills-demo/workspace`, with links back to this checkout's `skills/` folder. The clone command is shown as a viewer setup step because the recording checkout already exists. For installation across all projects, use the user-level destinations documented in `skills/README.md`. Each `ln -s` links into the client's skills folder, keeping the skill's folder name, and fails rather than overwriting if that name already exists; if a destination already exists, inspect it during rehearsal and reuse it if appropriate. Link individual skill folders, each containing `SKILL.md`.
|
|
93
|
+
|
|
94
|
+
Discovery locations and invocation syntax are documented in [Claude Code Skills](https://code.claude.com/docs/en/skills) and [OpenAI's Codex skills documentation](https://learn.chatgpt.com/docs/build-skills).
|
|
95
|
+
|
|
96
|
+
### 2:05–3:10 — Scenario 1: BGP health in Claude Code
|
|
97
|
+
|
|
98
|
+
**Screen:** In Claude Code, select `/check-bgp-health` and submit:
|
|
99
|
+
|
|
100
|
+
```text
|
|
101
|
+
/check-bgp-health Check the arista_ceos inventory group. Summarize neighbor states,
|
|
102
|
+
prefix counts, and uptime. Separate observed problems from possible causes,
|
|
103
|
+
and report any devices or checks you could not assess.
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Say while the request runs:**
|
|
107
|
+
|
|
108
|
+
> First: a fabric-wide BGP check. I'm choosing the skill explicitly and targeting the arista_ceos group, covering all eight switches.
|
|
109
|
+
>
|
|
110
|
+
> The skill asks for IPv4, IPv6, and EVPN summaries. The server queries the devices, and the assistant turns the results into a report.
|
|
111
|
+
|
|
112
|
+
**Screen:** Expand one `eos_run_show` call. Highlight the group target and command list, then return to the report.
|
|
113
|
+
|
|
114
|
+
**Say:**
|
|
115
|
+
|
|
116
|
+
> Notice the group target and the commands behind the answer. We can inspect the evidence.
|
|
117
|
+
>
|
|
118
|
+
> Look for Established sessions, prefix counts, and recent session starts. A short uptime means a session started recently; we need more evidence to call it repeated flapping.
|
|
119
|
+
>
|
|
120
|
+
> If a session is down, the skill can check neighbor details. A possible cause still needs supporting evidence.
|
|
121
|
+
|
|
122
|
+
**Presenter notes:** Point to actual values. If all sessions are Established, say “The queried sessions are Established in this snapshot.” If there is a failure, identify the observed state and any retrieved reset reason. Never narrate a specific cause unless the result supports it. Distinguish an explicitly unconfigured address family from an unsupported command or failed query.
|
|
123
|
+
|
|
124
|
+
### 3:10–4:15 — Scenario 2: Interface health in Codex
|
|
125
|
+
|
|
126
|
+
**Screen:** Switch to Codex. Select `$check-interface-health` and submit:
|
|
127
|
+
|
|
128
|
+
```text
|
|
129
|
+
$check-interface-health Check node2-1. Its expected uplinks are Ethernet1
|
|
130
|
+
toward node1-1 and Ethernet2 toward node1-2. Report observed link states
|
|
131
|
+
and descriptions, and flag any expected uplink that is down. This is a
|
|
132
|
+
cEOS containerlab: skip optics and physical hardware diagnostics. Treat
|
|
133
|
+
unused ports separately and report any checks you could not complete.
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Say:**
|
|
137
|
+
|
|
138
|
+
> Now let's use Codex to verify the links on node2-1. Codex uses a dollar sign to select the skill; Claude Code uses a slash. Both clients can use these same workflow files.
|
|
139
|
+
>
|
|
140
|
+
> This leaf has two expected uplinks: Ethernet1 toward node1-1, and Ethernet2 toward node1-2.
|
|
141
|
+
|
|
142
|
+
**Screen:** Show the initial `show interfaces status` and `show interfaces counters errors` tool inputs, followed by the report. Highlight `Ethernet1` and `Ethernet2` and compare their observed state and descriptions with the topology.
|
|
143
|
+
|
|
144
|
+
**Say:**
|
|
145
|
+
|
|
146
|
+
> Check whether both expected uplinks are connected. An unused, disconnected port elsewhere may be expected.
|
|
147
|
+
>
|
|
148
|
+
> The skill also reads error counters, but this container demo isn't a physical cable test. We're demonstrating link state, with no CRC errors expected.
|
|
149
|
+
>
|
|
150
|
+
> If both uplinks are up, that's a useful result: we've checked the expected connections and can inspect the evidence.
|
|
151
|
+
|
|
152
|
+
**Presenter notes:** A healthy report is the planned outcome; do not introduce a fault or wait for CRC errors. The topology defines the intended links, while the live tool output establishes their current state. Skip transceiver DOM, physical cable fault diagnosis, and ASIC resource checks in this cEOS demo.
|
|
153
|
+
|
|
154
|
+
### 4:15–4:40 — More usage scenarios
|
|
155
|
+
|
|
156
|
+
**Screen:** Show a prompt card rather than waiting for a third live workflow:
|
|
157
|
+
|
|
158
|
+
```text
|
|
159
|
+
Use check-route-health on node2-1. Summarize VRFs and route counts.
|
|
160
|
+
This is cEOS: skip hardware capacity checks. Flag unexpected empty
|
|
161
|
+
tables and state what you could not verify.
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**Say:**
|
|
165
|
+
|
|
166
|
+
> We also installed route health, which checks VRFs and routing tables.
|
|
167
|
+
>
|
|
168
|
+
> You can use these skills for morning checks, after maintenance, or to collect evidence for an incident. You can ask in ordinary language too; the assistant may select a matching skill. Naming it explicitly makes the workflow easier to follow in a demo.
|
|
169
|
+
|
|
170
|
+
### 4:40–5:00 — Close
|
|
171
|
+
|
|
172
|
+
**Screen:** Return to the skill file beside one completed report. End card: repository link and “Read the runbook • Choose a target • Inspect the results.”
|
|
173
|
+
|
|
174
|
+
**Say:**
|
|
175
|
+
|
|
176
|
+
> To get started, connect the EOS MCP server, install the skill folders, and choose a target from your inventory.
|
|
177
|
+
>
|
|
178
|
+
> The server provides the device tools. Skills turn those tools into reusable workflows you can inspect and share.
|
|
179
|
+
>
|
|
180
|
+
> The repository, setup instructions, and example prompts are linked below. Try one check in your lab and inspect the results.
|
|
181
|
+
|
|
182
|
+
## Presenter preparation — outside the five-minute cut
|
|
183
|
+
|
|
184
|
+
### Prerequisites and lab
|
|
185
|
+
|
|
186
|
+
- Bash on Linux, macOS, or WSL; Git; Node.js **24+**, as required by the current `package.json`.
|
|
187
|
+
- Claude Code and Codex CLI installed, signed in, and ready. Use their official setup guides for client installation.
|
|
188
|
+
- The existing `clab/testlab.clab.yaml` containerlab, with HTTPS eAPI reachable on all eight cEOS nodes and credentials authorized to run the checks.
|
|
189
|
+
- The lab's routing configuration already deployed. The topology alone defines nodes and links; it does not establish BGP configuration or live neighbor health. Rehearse against the deployed lab; IPv6 BGP may be unconfigured.
|
|
190
|
+
- A sanitized inventory and terminal layout suitable for publication. Enter credentials off camera and keep saved credential configuration out of the recording.
|
|
191
|
+
|
|
192
|
+
Use a disposable demo workspace or a dedicated recording account so unrelated MCP servers and duplicate skill names do not clutter the selectors. Rehearse both clients against the same lab. No fault is required for a useful demo.
|
|
193
|
+
|
|
194
|
+
### Use the existing config and containerlab inventory
|
|
195
|
+
|
|
196
|
+
Use `example-codex/eos-mcp-server-config.yml` unchanged for this recording. It contains:
|
|
197
|
+
|
|
198
|
+
```yaml
|
|
199
|
+
inventory: /home/fred/aristanetworks/eos-mcp-server/clab/ansible-inventory.yml
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
The inventory defines group **`arista_ceos`** with `node1-1`, `node1-2`, and `node2-1` through `node2-6`. It supplies the `admin` username, `EOS_MCP_PASSWORD` password reference, and disabled certificate validation for the lab. Use the existing password for these devices.
|
|
203
|
+
|
|
204
|
+
The topology specifies `ceos-lab:4.34.3M` and connects each leaf to both spines. The selected leaf's intended links are:
|
|
205
|
+
|
|
206
|
+
| Leaf interface | Spine interface |
|
|
207
|
+
| --- | --- |
|
|
208
|
+
| `node2-1:Ethernet1` | `node1-1:Ethernet1` |
|
|
209
|
+
| `node2-1:Ethernet2` | `node1-2:Ethernet1` |
|
|
210
|
+
|
|
211
|
+
`clab/` is ignored by Git in this checkout. A fresh public clone supplies the skills but does not supply this local lab. The recording uses the existing checkout; viewers using another lab must provide their own inventory and adjust the absolute inventory path in their server config.
|
|
212
|
+
|
|
213
|
+
In Bash, enter the password without placing its literal value in shell history:
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
read -rsp 'EOS lab password: ' EOS_MCP_PASSWORD
|
|
217
|
+
printf '\n'
|
|
218
|
+
export EOS_MCP_PASSWORD
|
|
219
|
+
|
|
220
|
+
# Recording checkout; viewers substitute their own checkout/config path.
|
|
221
|
+
EOS_DEMO_REPO="/home/fred/aristanetworks/eos-mcp-server"
|
|
222
|
+
EOS_DEMO_CONFIG="$EOS_DEMO_REPO/example-codex/eos-mcp-server-config.yml"
|
|
223
|
+
|
|
224
|
+
npx -y @aristanetworks/eos-mcp-server validate-inventory \
|
|
225
|
+
--config "$EOS_DEMO_CONFIG"
|
|
226
|
+
|
|
227
|
+
npx -y @aristanetworks/eos-mcp-server probe \
|
|
228
|
+
--config "$EOS_DEMO_CONFIG" --target arista_ceos
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
`validate-inventory` checks inventory and connection settings, including password resolution; it does not contact the devices. `probe` makes live device requests. Proceed to recording once all eight devices probe successfully.
|
|
232
|
+
|
|
233
|
+
### Register the server in both clients
|
|
234
|
+
|
|
235
|
+
Run these commands in the same shell as the exported password and absolute config path. Both clients use the config in `example-codex`. Register the server as **`eos`** because the skill files refer to that server's tools.
|
|
236
|
+
|
|
237
|
+
**Claude Code:**
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
claude mcp add --scope user --transport stdio eos \
|
|
241
|
+
--env EOS_MCP_PASSWORD="$EOS_MCP_PASSWORD" \
|
|
242
|
+
-- npx -y @aristanetworks/eos-mcp-server serve \
|
|
243
|
+
--config "$EOS_DEMO_CONFIG"
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
**Codex:**
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
codex mcp add eos \
|
|
250
|
+
--env EOS_MCP_PASSWORD="$EOS_MCP_PASSWORD" \
|
|
251
|
+
-- npx -y @aristanetworks/eos-mcp-server serve \
|
|
252
|
+
--config "$EOS_DEMO_CONFIG"
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
These CLI examples store the expanded password in each client's saved configuration. Keep those files private and off camera. For Codex, you can instead configure dynamic environment forwarding in `~/.codex/config.toml`:
|
|
256
|
+
|
|
257
|
+
```toml
|
|
258
|
+
[mcp_servers.eos]
|
|
259
|
+
command = "npx"
|
|
260
|
+
args = ["-y", "@aristanetworks/eos-mcp-server", "serve", "--config", "/home/fred/aristanetworks/eos-mcp-server/example-codex/eos-mcp-server-config.yml"]
|
|
261
|
+
env_vars = ["EOS_MCP_PASSWORD"]
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Use this TOML table as an alternative to the CLI-created entry, replacing its stored `env` password entry; do not append a duplicate table. Launch Codex from a shell where the password is exported. See the [Codex MCP documentation](https://learn.chatgpt.com/docs/extend/mcp?surface=cli) and [Claude Code MCP documentation](https://code.claude.com/docs/en/mcp) for client configuration details.
|
|
265
|
+
|
|
266
|
+
The MCP client launches the server; you do not need a separate foreground `serve` process. Download the npm package during rehearsal. For repeatable recordings, choose and pin a released package version in both client commands and record the Git commit used for the skills.
|
|
267
|
+
|
|
268
|
+
### Verify installation before recording
|
|
269
|
+
|
|
270
|
+
1. Run the skill-link commands from the recording script. If a skill already exists, inspect its destination rather than overwriting it.
|
|
271
|
+
2. Launch `claude` and `codex` in separate terminals. In each client, check `/mcp` for the `eos` server and its tools.
|
|
272
|
+
3. Confirm the three skill names appear: type `/check-` in Claude Code; use `/skills` or `$check-` in Codex. Restart a client if newly added skills are missing.
|
|
273
|
+
4. Ask each client: “Use eos_list_inventory to list the available EOS hosts and groups.” Confirm all eight lab nodes and the `arista_ceos` group appear.
|
|
274
|
+
5. Rehearse both prompts. Confirm the assistant loads the named skill and calls EOS MCP tools rather than answering from general knowledge.
|
|
275
|
+
|
|
276
|
+
## Prompt reference and optional follow-ups
|
|
277
|
+
|
|
278
|
+
| Scenario | Claude Code | Codex |
|
|
279
|
+
| --- | --- | --- |
|
|
280
|
+
| Fabric BGP health | `/check-bgp-health Check arista_ceos.` | `$check-bgp-health Check arista_ceos.` |
|
|
281
|
+
| Virtual uplink state | `/check-interface-health Check node2-1 uplinks Ethernet1 and Ethernet2; skip optics.` | `$check-interface-health Check node2-1 uplinks Ethernet1 and Ethernet2; skip optics.` |
|
|
282
|
+
| Routing and VRFs | `/check-route-health Check VRFs and route counts on node2-1; skip hardware checks.` | `$check-route-health Check VRFs and route counts on node2-1; skip hardware checks.` |
|
|
283
|
+
|
|
284
|
+
Useful follow-ups in either client:
|
|
285
|
+
|
|
286
|
+
```text
|
|
287
|
+
Which findings are directly supported by device output, and which are hypotheses?
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
```text
|
|
291
|
+
Recheck Ethernet1 and Ethernet2 on node2-1. Compare their current link states
|
|
292
|
+
with the previous reading and summarize any changes. Keep this read-only.
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
```text
|
|
296
|
+
Summarize the results in five lines for an incident handoff, including targets,
|
|
297
|
+
observations, checks that failed, and the next read-only investigation.
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
The repository also has EVPN, Port-Channel, VLAN, multicast, PTP, and Segment Routing workflows. Introduce these as follow-up topics; keep the first video focused on the two live checks.
|
|
301
|
+
|
|
302
|
+
## Recording contingencies
|
|
303
|
+
|
|
304
|
+
| What happens | Presenter response |
|
|
305
|
+
| --- | --- |
|
|
306
|
+
| Everything looks healthy | Explain the observed states and counts. A healthy lab is a valid demonstration. |
|
|
307
|
+
| Interface counters are all zero | Continue with the expected-uplink state check. CRC faults and optics alarms are not expected demonstrations in this container lab. |
|
|
308
|
+
| Skill missing from a selector | Check the per-skill link and `SKILL.md`, then restart the client. Fix this during rehearsal. |
|
|
309
|
+
| Server connected, devices unreachable | Check inventory, eAPI reachability, credentials, and TLS. A connected MCP server does not establish device connectivity. |
|
|
310
|
+
| An EOS command is unsupported | Report that check as unavailable. Do not convert a command failure into a healthy result or a missing-feature claim. |
|
|
311
|
+
| A skill overstates a cause | Point back to the evidence and ask it to separate observations from hypotheses. |
|
|
312
|
+
| A tool call takes too long for the edit | Trim the wait while retaining the submitted prompt, an actual tool call, and the returned report. |
|
|
313
|
+
|
|
314
|
+
Keep screenshots from a successful rehearsal as a fallback, clearly labeled “recorded lab result” if inserted. Do not substitute fabricated device output. Show one short tool trace per client and spend the remaining time explaining the reports.
|
|
315
|
+
|
|
316
|
+
## Suggested video description
|
|
317
|
+
|
|
318
|
+
```text
|
|
319
|
+
Learn what AI skills are and use them with the Arista EOS MCP server in
|
|
320
|
+
Claude Code and Codex. We install shared workflow files, then check BGP
|
|
321
|
+
neighbors and virtual uplink state against an eight-node cEOS containerlab.
|
|
322
|
+
Both clients use example-codex/eos-mcp-server-config.yml and the local
|
|
323
|
+
clab inventory. This demo does not depend on CRC errors or physical optics.
|
|
324
|
+
|
|
325
|
+
00:00 What we'll build
|
|
326
|
+
00:20 Skills and MCP explained
|
|
327
|
+
00:55 The lab
|
|
328
|
+
01:15 Install skills for Claude Code and Codex
|
|
329
|
+
02:05 BGP health in Claude Code
|
|
330
|
+
03:10 Interface health in Codex
|
|
331
|
+
04:15 More workflows
|
|
332
|
+
04:40 Getting started
|
|
333
|
+
|
|
334
|
+
Repository: https://github.com/aristanetworks/eos-mcp-server
|
|
335
|
+
Skills and installation: https://github.com/aristanetworks/eos-mcp-server/tree/main/skills
|
|
336
|
+
Server setup: https://github.com/aristanetworks/eos-mcp-server#connect-to-an-mcp-client
|
|
337
|
+
|
|
338
|
+
Requires reachable Arista EOS devices with eAPI, Node.js 24+, and your
|
|
339
|
+
chosen AI client. These workflows use read-only device tools.
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
Adjust chapter timestamps to match the final edit.
|
|
343
|
+
|
|
344
|
+
## Verification notes
|
|
345
|
+
|
|
346
|
+
Prepared against this checkout's `skills/README.md`, the BGP/interface/route skill files, MCP tool schemas, CLI implementation, and `package.json`. Lab targets and intended links were checked against `example-codex/eos-mcp-server-config.yml`, `clab/ansible-inventory.yml`, and `clab/testlab.clab.yaml`. Client registration syntax was checked with installed Codex CLI 0.163.0 and Claude Code 2.1.306 help, and skill discovery/invocation was checked against the linked official documentation. Live lab outputs and recording timings must be rehearsed in the presenter's environment.
|
package/docs/DESIGN.md
CHANGED
|
@@ -48,19 +48,19 @@ Canonical Ansible-style YAML and simplified YAML are supported. Structural keys
|
|
|
48
48
|
|
|
49
49
|
## Runtime controls
|
|
50
50
|
|
|
51
|
-
Read requests have configured per-device timeout, optional overall timeout,
|
|
51
|
+
Read requests have configured per-device timeout, optional overall timeout, per-call fan-out (`readFanOut`), target-count, command-count, logging-message, and response-size limits. The overall timeout aborts in-flight requests and halts further scheduling. Every eAPI request, read or diagnostic, holds one of its device's `deviceConcurrency` slots, shared across all calls in the server process ([ADR 0009](adr/0009-shared-per-device-eapi-slots.md)); `readTimeoutMs` starts once the slot is granted. Device HTTP responses and final serialized tool results are size-limited.
|
|
52
52
|
|
|
53
53
|
### Active diagnostic controls
|
|
54
54
|
|
|
55
|
-
`eos_ping` uses independent `diagnostics` settings with finite defaults: count 3/max 10, aggregate probes 100 (hosts × destinations × count), 16 destinations per call,
|
|
55
|
+
`eos_ping` uses independent `diagnostics` settings with finite defaults: count 3/max 10, aggregate probes 100 (hosts × destinations × count), 16 destinations per call, per-device concurrency 2 (within the shared per-device limit of 3) under a per-server ceiling of 32, reply timeout 1000 ms, command budget 30000 ms, HTTP timeout 35000 ms, and overall timeout 60000 ms. All are configurable; target and response-size limits are shared with reads. Config validation requires consistent counts, execution budgets, and HTTP timeouts.
|
|
56
56
|
|
|
57
|
-
A ping request names one or more destinations and sends exactly one text-mode eAPI request per host and destination, without automatic retries. Those executions run concurrently under the shared admission controller, each with its own reservation, and return one result per host and destination. Fixed count, one-second interval, fixed size 64, and reply timeout bound device work;
|
|
57
|
+
A ping request names one or more destinations and sends exactly one text-mode eAPI request per host and destination, without automatic retries. Those executions run concurrently under the shared admission controller, which limits each device separately under a server-wide ceiling ([ADR 0007](adr/0007-per-device-diagnostic-concurrency.md)), each with its own reservation, and return one result per host and destination. Fixed count, one-second interval, fixed size 64, and reply timeout bound device work; by default each request also carries EOS `requestTimeout` set to the command budget (`diagnostics.nativeRequestTimeout`), which interrupts execution on the device but does not cover time queued before execution. HTTP abort is not proof of remote completion. Unknown completion holds its admission slot for the command budget, then frees it; a late confirmed response frees it sooner. Capacity is held in memory per server process, so several servers can use one inventory at once ([ADR 0006](adr/0006-in-memory-timed-diagnostic-capacity.md)). Server info exposes current sanitized capacity and reservation state. A qualified native remote deadline remains unresolved; timeout-shaped RPC errors are not assumed to confirm process exit. Cancellation stops scheduling and aborts HTTP requests; overall timeout remains a request-level failure without partial results. Every tool, ping included, advertises MCP `readOnlyHint: true` so clients may run independent calls concurrently; these server-side limits, not client scheduling, bound the load ([ADR 0008](adr/0008-read-only-tool-annotations.md)). See [DIAGNOSTICS.md](DIAGNOSTICS.md) for the full lifecycle assumptions and limits.
|
|
58
58
|
|
|
59
59
|
Only unicast literal destinations are supported; DNS, scoped/link-local IPv6, multicast, unspecified, and limited broadcast addresses are rejected. Optional VRF/source selection must not fall back. Directed-broadcast detection is not guaranteed from an address alone.
|
|
60
60
|
|
|
61
61
|
## Result and error model
|
|
62
62
|
|
|
63
|
-
Every eAPI response must identify JSON-RPC 2.0, match its request ID exactly, and contain exactly one result/error member before interpretation. Missing or mismatched identity is `eapi_response_uncorrelated`, not completion evidence.
|
|
63
|
+
Every eAPI response must identify JSON-RPC 2.0, match its request ID exactly, and contain exactly one result/error member before interpretation. Missing or mismatched identity is `eapi_response_uncorrelated`, not completion evidence. Each diagnostic execution's reservation ID is its wire ID. Correlation IDs do not provide an EOS job lookup, cancellation, or idempotency facility.
|
|
64
64
|
|
|
65
65
|
Device-facing tools return target metadata, resolved devices, summary counts, and per-device results. Request-level failures and known device failures use `AppError` machine-readable codes. Supported read tools expose raw eAPI payloads only through an explicit `include_raw` option. Ping separates successful execution from a reachability finding and returns normalized loss/RTT measurements; original EOS text is opt-in. Unrecognized output is an explicit device failure, never an invented finding.
|
|
66
66
|
|
package/docs/DIAGNOSTICS.md
CHANGED
|
@@ -58,11 +58,13 @@ diagnostics:
|
|
|
58
58
|
maxPingCount: 10
|
|
59
59
|
maxProbesPerRequest: 100
|
|
60
60
|
maxDestinationsPerRequest: 16
|
|
61
|
-
deviceConcurrency:
|
|
61
|
+
deviceConcurrency: 2
|
|
62
|
+
maxConcurrentDiagnostics: 32
|
|
62
63
|
pingReplyTimeoutMs: 1000
|
|
63
64
|
commandTimeoutMs: 30000
|
|
64
65
|
httpTimeoutMs: 35000
|
|
65
66
|
overallOperationTimeoutMs: 60000
|
|
67
|
+
nativeRequestTimeout: true
|
|
66
68
|
```
|
|
67
69
|
|
|
68
70
|
| Setting | Meaning |
|
|
@@ -71,13 +73,15 @@ diagnostics:
|
|
|
71
73
|
| `maxPingCount` | Maximum probes per device and destination |
|
|
72
74
|
| `maxProbesPerRequest` | Maximum resolved host count × destination count × requested probes |
|
|
73
75
|
| `maxDestinationsPerRequest` | Maximum destinations in one `eos_ping` call |
|
|
74
|
-
| `deviceConcurrency` |
|
|
76
|
+
| `deviceConcurrency` | Diagnostic slots one inventory host may hold across all calls, counting active and uncertain executions; must not exceed `maxConcurrentDiagnostics` or the top-level `deviceConcurrency`, the host's eAPI slots shared with reads |
|
|
77
|
+
| `maxConcurrentDiagnostics` | Diagnostic slots of one server process across all devices and calls |
|
|
75
78
|
| `pingReplyTimeoutMs` | EOS per-reply timeout; a positive multiple of 1000 ms |
|
|
76
79
|
| `commandTimeoutMs` | Conservative device execution budget; see lifecycle below |
|
|
77
80
|
| `httpTimeoutMs` | Per-device diagnostic eAPI HTTP timeout, separate from `readTimeoutMs` |
|
|
78
|
-
| `overallOperationTimeoutMs` | Whole diagnostic call deadline, including waiting for
|
|
81
|
+
| `overallOperationTimeoutMs` | Whole diagnostic call deadline, including waiting for per-device and server-wide capacity |
|
|
82
|
+
| `nativeRequestTimeout` | Send EOS `runCmds.requestTimeout` set to `commandTimeoutMs`, so the device interrupts a ping that outlives its budget; set `false` for an EOS version that rejects the field |
|
|
79
83
|
|
|
80
|
-
|
|
84
|
+
Diagnostic capacity is held in memory by each server process; nothing is written to disk. Several MCP servers (for example two chat sessions) can run against the same inventory at once, each with its own `deviceConcurrency` and `maxConcurrentDiagnostics`. The former `diagnostics.stateFile` setting is rejected with guidance; delete it. Ledger files left under `$XDG_STATE_HOME/eos-mcp-server/` (or `~/.local/state/eos-mcp-server/`) by earlier versions are no longer read and can be deleted. See [ADR 0006](adr/0006-in-memory-timed-diagnostic-capacity.md).
|
|
81
85
|
|
|
82
86
|
Existing `maxReadTargets` (default 50) and `maxResponseSizeBytes` (default 1,048,576) also apply. Diagnostic concurrency and timeouts are independent of the corresponding read settings. Effective diagnostic settings are reported by `eos_get_server_info` under `limits.diagnostics`.
|
|
83
87
|
|
|
@@ -91,84 +95,34 @@ The HTTP timeout must exceed the command budget by at least 1000 ms. Individual
|
|
|
91
95
|
|
|
92
96
|
## Execution and lifecycle
|
|
93
97
|
|
|
94
|
-
Each host/destination execution is one text-mode eAPI request containing `enable` followed by the generated ping command. The
|
|
98
|
+
Each host/destination execution is one text-mode eAPI request containing `enable` followed by the generated ping command. The reservation ID is used as the exact wire request ID. All eAPI responses, including read-tool responses, must use JSON-RPC 2.0, match the exact request ID, and contain exactly one `result` or `error` member. Missing/stale identity fails with `eapi_response_uncorrelated`; contradictory envelopes fail with `eapi_payload_invalid`. Neither is completion evidence, and an unrelated response is never exposed as the requested diagnostic's raw output. There are **no automatic ping retries**, including no JSON-to-text retry. Read-only auto fallback also requires a correlated error and uses a new ID for its subsequent request. Existing `eos_run_show` validation remains show-only.
|
|
95
99
|
|
|
96
|
-
On cEOS 4.34.3M, ping's `timeout` maps to a per-reply wait, not a whole-process deadline. The tool combines finite `repeat`, explicit one-second `interval`, and finite reply timeout; the conservative execution formula above must fit `commandTimeoutMs`. This budget is **not** a remote wall-clock kill timer. It assumes normal EOS command scheduling, not a stalled operating system or an indefinitely queued eAPI command. No remote process termination guarantee is made.
|
|
100
|
+
On cEOS 4.34.3M, ping's `timeout` maps to a per-reply wait, not a whole-process deadline. The tool combines finite `repeat`, explicit one-second `interval`, and finite reply timeout; the conservative execution formula above must fit `commandTimeoutMs`. This budget is **not** a remote wall-clock kill timer. It assumes normal EOS command scheduling, not a stalled operating system or an indefinitely queued eAPI command. No remote process termination guarantee is made. The same budget is how long an uncertain slot is held (below).
|
|
97
101
|
|
|
98
|
-
One admission controller is shared by
|
|
102
|
+
One admission controller is shared by every eAPI request in a server process, reads and diagnostics alike ([ADR 0009](adr/0009-shared-per-device-eapi-slots.md)). It grants a diagnostic slot only while the device holds fewer than the top-level `deviceConcurrency` slots in total, fewer than `diagnostics.deviceConcurrency` diagnostic slots, and the process holds fewer than `maxConcurrentDiagnostics`. Because the diagnostic share is below the device total, pings can never fill a device and hold up its reads. Waiters are served oldest first, skipping any that cannot run yet, so a ping waiting on a busy device never holds up a later one to a free device ([ADR 0007](adr/0007-per-device-diagnostic-concurrency.md)). A slot is reserved **before** the device runner can dispatch. Confirmed synchronous completion or a locally established rejection before dispatch frees it immediately. Unknown completion after transport loss, HTTP timeout, invalid eAPI payload (including correlated results with missing or non-text output), cancellation, or a post-dispatch RPC error becomes **uncertain**: the slot stays held for `commandTimeoutMs` from that moment, then frees itself. A late confirmed response frees it sooner. RPC interruption errors are not treated as proof of completion. Restarting the server forgets uncertain slots; under normal scheduling the original command has finished within `commandTimeoutMs` of dispatch anyway. If EOS ever queued a request for longer than that, replacement work could overlap it; [ADR 0006](adr/0006-in-memory-timed-diagnostic-capacity.md) accepts that bounded risk for ping.
|
|
99
103
|
|
|
100
|
-
|
|
104
|
+
A request fans out into one execution per resolved host and destination. All of them queue with the same admission controller as every other call at once; each takes and releases its own reservation exactly as a single ping does. Different devices run in parallel, each up to `deviceConcurrency`, within `maxConcurrentDiagnostics` for the whole process. Queued executions wait for capacity inside the same overall deadline, so size requests so that roughly `ceil(destinations / deviceConcurrency)` successive waves of pings per host fit within `overallOperationTimeoutMs`. That estimate assumes the server ceiling has room: once hosts × destinations, plus the executions of other concurrent calls, exceed `maxConcurrentDiagnostics`, waves also wait on the ceiling. Uncertain reservations reduce both device and server capacity. On cEOS 4.34.3M eAPI ran at most three requests at once per device, pings and reads combined; further delivered requests, including show commands, waited on the device. The top-level `deviceConcurrency` default of 3 matches that, and the diagnostic default of 2 keeps one slot for reads. Set the top-level value to the device's own eAPI concurrency for other platforms.
|
|
101
105
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
The overall deadline or MCP cancellation stops scheduling new executions, removes capacity waiters, and aborts in-flight HTTP work. Every in-flight execution of a cancelled multi-destination request becomes uncertain, so one cancellation can hold up to `deviceConcurrency` slots; queued executions are never dispatched. An overall timeout is a request-level `operation_timeout`, not a partial-results response. Already completed findings are not returned on that path. Do not blindly retry an interrupted diagnostic.
|
|
106
|
+
The overall deadline or MCP cancellation stops scheduling new executions, removes capacity waiters, and aborts in-flight HTTP work. Every in-flight execution of a cancelled multi-destination request becomes uncertain, so one cancellation can hold up to `deviceConcurrency` slots on each targeted device for up to `commandTimeoutMs`; queued executions of that request are never dispatched. An overall timeout is a request-level `operation_timeout`, not a partial-results response. Already completed findings are not returned on that path. Do not blindly retry an interrupted diagnostic.
|
|
105
107
|
|
|
106
108
|
## Uncertain execution and capacity visibility
|
|
107
109
|
|
|
108
|
-
`eos_get_server_info` returns a fresh `diagnostics.capacity` snapshot with:
|
|
110
|
+
`eos_get_server_info` returns a fresh `diagnostics.capacity` snapshot for that server process with:
|
|
109
111
|
|
|
110
|
-
- `
|
|
111
|
-
- `active_count`, `uncertain_count`, and `queued_count`.
|
|
112
|
-
- `
|
|
113
|
-
- `
|
|
112
|
+
- `limit` (`maxConcurrentDiagnostics`), `device_limit` (`diagnostics.deviceConcurrency`), `eapi_device_limit` (top-level `deviceConcurrency`), and server-wide `available_count`.
|
|
113
|
+
- Server-wide `active_count`, `uncertain_count`, and `queued_count`.
|
|
114
|
+
- `devices`: for each inventory host holding or awaiting a slot, its diagnostic `available_count` (its diagnostic headroom, capped by its shared eAPI headroom and server-wide availability), `active_count`, `uncertain_count`, and `queued_count`, plus the read slots it holds and awaits (`read_active_count`, `read_queued_count`).
|
|
115
|
+
- `reservations`: ID (also the wire RPC ID), inventory hostname, diagnostic kind, state, reservation timestamp, and (when uncertain) uncertainty timestamp, `releases_at`, and machine-readable reason code. Destinations, endpoints, credentials, and original EOS output are not included.
|
|
114
116
|
|
|
115
|
-
|
|
117
|
+
Uncertain slots count against their device's `deviceConcurrency` and against `maxConcurrentDiagnostics` like active ones. New work for that device queues behind them and is dispatched when a slot frees, within the overall deadline; if the deadline expires first the call fails with `operation_timeout`. Other devices keep running without waiting for them.
|
|
116
118
|
|
|
117
119
|
The standalone `print-server-info` CLI has no live executor and reports `diagnostics.capacity: null`, not fabricated available capacity. Inspect the running MCP server for actual reservation state.
|
|
118
120
|
|
|
119
|
-
### Offline inspection and operator recovery
|
|
120
|
-
|
|
121
|
-
```bash
|
|
122
|
-
eos-mcp-server inspect-diagnostics --config eos-mcp-server.yml --json
|
|
123
|
-
# Or derive the default ledger from the same inventory identity:
|
|
124
|
-
eos-mcp-server inspect-diagnostics --inventory inventory.yml --json
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
Inspection opens existing state read-only, including while another server owns it; it does not resolve credentials, contact devices, take over ownership, create a missing ledger, or clear records. Integrity, schema, reservations, and audit are read in one transaction, so a concurrent commit cannot mix before/after release states. A competing writer may fail closed while this short read snapshot is held; inspect current state before retrying an administrative release. Inspection reports recorded state, not proof that remote work completed.
|
|
128
|
-
|
|
129
|
-
**Operational constraints:** use a persistent local filesystem that honors SQLite locking and sync, private owner-controlled state files (POSIX mode 0600), and an owner-controlled directory not writable by group/others. Network filesystems and ephemeral/container storage are not qualified durability mechanisms. Preserve the ledger, its `.lock.sqlite` ownership file, and any SQLite recovery files together. Do not delete, replace, copy, rotate, roll back, or change the ledger path to clear reservations. Loss of both ledger files cannot be distinguished locally from first initialization. Before upgrading from the earlier in-memory implementation, unresolved old executions require independent reconciliation; they cannot be recovered from a journal that did not yet exist.
|
|
130
|
-
|
|
131
|
-
Restarting with the same ledger retains uncertainty. Recovery is now available only as an **offline, audited Operator Release** backed by a **Fencing Attestation**. There is no MCP reset, release-all operation, native completion-token lookup, or automatic timeout-based release. Stopping the MCP process establishes local ownership transfer, not remote termination.
|
|
132
|
-
|
|
133
|
-
#### Operator release workflow
|
|
134
|
-
|
|
135
|
-
1. Stop the server owning this ledger and prevent diagnostic resubmission. The release command refuses a live ledger owner; it does not stop one.
|
|
136
|
-
2. Run `inspect-diagnostics --json` and retain the `inventory_identity`, exact selected reservation IDs, immutable host/admission timestamps, and recorded RPC IDs. Establish the original physical device and execution epoch from independent evidence/history, not just today's inventory mapping.
|
|
137
|
-
3. Independently verify that the fence terminates running work, invalidates **accepted queued** work, and prevents later dispatch/replay. A timeout, empty process list, quiet counters, or repeated observations are insufficient.
|
|
138
|
-
4. Prepare a private JSON attestation from [the deliberately invalid template](examples/diagnostic-release-evidence.template.json). Replace every placeholder with actual evidence. Change each assertion to true only after verification. Do not put credentials, raw packet contents, or EOS output in the file; use evidence references instead.
|
|
139
|
-
5. Release only the exact covered IDs, then inspect the audit:
|
|
140
|
-
|
|
141
|
-
```bash
|
|
142
|
-
# Prepare with private permissions; the template cannot authorize a release as-is.
|
|
143
|
-
umask 077
|
|
144
|
-
cp docs/examples/diagnostic-release-evidence.template.json ./evidence.json
|
|
145
|
-
# Human: complete the attestation from independently verified fencing evidence.
|
|
146
|
-
chmod 600 ./evidence.json
|
|
147
|
-
|
|
148
|
-
eos-mcp-server release-diagnostics --config eos-mcp-server.yml \
|
|
149
|
-
--reservation-id '<exact-id>' --evidence-file ./evidence.json \
|
|
150
|
-
--confirm-fenced --json
|
|
151
|
-
# Repeat --reservation-id only for other IDs covered by the same attestation.
|
|
152
|
-
eos-mcp-server inspect-diagnostics --config eos-mcp-server.yml --json
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
`--confirm-fenced`, an evidence file, and explicit unique IDs are mandatory. Evidence is private, owner-controlled UTF-8 JSON with unique keys, at most 65536 bytes and 100 explicitly covered reservations. There is no wildcard selection. The command performs no credential resolution, device call, URI fetch, fencing action, or network retry. A state-only config with an explicit `diagnostics.stateFile` can be used if the original inventory is unavailable; the attestation still must match the ledger's stored inventory identity. If config declares an inventory path, its canonical identity must also match.
|
|
156
|
-
|
|
157
|
-
The attestation requires `evidence_version: 1`, a new UUID `attestation_id`, the exact `inventory_identity`, an accountable `verified_by`, a past UTC `verified_at`, a reason, and four literal-true assertions: `independent_evidence_verified`, `running_work_terminated`, `accepted_queued_work_cannot_execute`, and `replay_prevented`. Each covered reservation must match its exact ID, host and `reserved_at`, and its exact `rpc_request_id` (explicit JSON null for legacy records without one). It must also identify the physical device, fenced execution epoch, fencing time, and independent evidence reference. Fencing must follow reservation admission and precede verification. The selected CLI IDs and evidence scope must match exactly.
|
|
158
|
-
|
|
159
|
-
#### Audit and authority
|
|
160
|
-
|
|
161
|
-
The release audit and every selected deletion commit in **one FULL-synchronous SQLite transaction** under exclusive ledger ownership. A failed batch rolls back earlier deletions and its audit; unselected reservations remain held. The append-only-through-the-application audit records original reservation snapshots, the complete attestation, its canonical SHA-256 digest, an audit-content checksum, server recording time, and actual local OS username/UID. `verified_by` is a claimed accountable person, not authenticated identity; the OS account is collected independently. Local operators must be trusted and protected by OS access controls. This is not a cryptographic human-presence check, and an untrusted agent with the ledger owner's filesystem privileges is outside that protection.
|
|
162
|
-
|
|
163
|
-
`inspect-diagnostics --json` exposes `release_audit` to local operators; MCP server info does not expose the evidence or audit. Checksums detect accidental inconsistency, not deliberate tampering by the trusted filesystem owner. The program validates consistency and explicit authority; it **cannot establish the truth of external fencing evidence**. Releasing on false attestation can violate remote concurrency safety.
|
|
164
|
-
|
|
165
|
-
If CLI completion is lost, inspect the audit first. Repeating the exact committed attestation returns its original release ID with `already_committed: true` and makes no additional changes. Reusing an attestation UUID for changed evidence is rejected. This local administrative idempotency does not make EOS ping requests idempotent; never retry a ping just because its RPC ID is known.
|
|
166
|
-
|
|
167
|
-
Ledger schema 1 upgrades atomically to schema 2, preserving unresolved reservations and adding release history. Read-only inspection of schema 1 does not migrate it. A rejected release also rolls back any migration. Schema-2 ledgers with missing or invalid audit history fail closed, and older schema-1-only binaries must not be used to bypass the audit.
|
|
168
|
-
|
|
169
121
|
### Native EOS timeout qualification
|
|
170
122
|
|
|
171
|
-
The installed cEOS implementation exposes a `runCmds.requestTimeout` execution-stage interruption timer. It was accepted in a bounded read request, and a later loopback experiment observed an interruption response after 273 ms with a 250 ms native timer (RPC code 1001 / error 408). No ping process appeared in the subsequent samples. This single normal-load result does not qualify a dispatch-relative or process-exit deadline, nor establish the public support contract.
|
|
123
|
+
The installed cEOS implementation exposes a `runCmds.requestTimeout` execution-stage interruption timer. It was accepted in a bounded read request, and a later loopback experiment observed an interruption response after 273 ms with a 250 ms native timer (RPC code 1001 / error 408). No ping process appeared in the subsequent samples. This single normal-load result does not qualify a dispatch-relative or process-exit deadline, nor establish the public support contract.
|
|
124
|
+
|
|
125
|
+
Ping requests now send `requestTimeout` equal to `commandTimeoutMs` (in seconds) by default, so EOS also stops a command that outlives its budget. Re-checked on the cEOS 4.34.3M lab: a 4-probe loopback ping with a 30 s timeout completed normally in about 3.1 s; with 0.25 s EOS returned RPC 1001 / error 408 after 264 ms and no ping process remained on the device. The timer starts only when EOS begins executing the command, so it does not cover time a request spends queued before that. A timeout-shaped RPC error is still treated as unknown completion and holds the slot like any other uncertain execution. Other EOS versions and physical platforms have not been checked; if one rejects the field, every ping fails with an RPC error, and `diagnostics.nativeRequestTimeout: false` turns it off. No durable token-bound status/cancel method was qualified. See [the primary-source investigation](research/eos-diagnostic-lifecycle.md) for evidence, citations, and limits.
|
|
172
126
|
|
|
173
127
|
## Results
|
|
174
128
|
|
|
@@ -183,11 +137,11 @@ Execution `status: "success"` means ping executed and its output was understood.
|
|
|
183
137
|
|
|
184
138
|
## Extension seam
|
|
185
139
|
|
|
186
|
-
`DiagnosticExecutor.execute` accepts typed diagnostic intent and owns authorization, aggregate budgets, fan-out, fail-closed
|
|
140
|
+
`DiagnosticExecutor.execute` accepts typed diagnostic intent and owns authorization, aggregate budgets, fan-out, fail-closed per-device and server-wide admission, cancellation, result envelopes, and response limits. `getCapacity()` exposes a detached snapshot; server-info obtains it at call time rather than caching startup state. `DiagnosticDeviceRunner.execute` accepts inventory identity and one prepared execution; the eAPI adapter owns connection resolution and a single command execution.
|
|
187
141
|
|
|
188
142
|
Each diagnostic kind supplies a `DiagnosticDefinition`: `prepare` validates the whole request before dispatch and returns the echoed request plus the executions every resolved host performs, `probeCount` prices one execution against the aggregate budget, and `interpret` turns observed output into a finding. The executor runs every prepared execution on every host and knows nothing kind-specific. Ping's definition, validation, compilation, and interpretation live in `src/diagnostics/ping.ts`; it prepares one execution per destination. Multiple destinations are therefore a property of ping's definition, not of the executor.
|
|
189
143
|
|
|
190
|
-
Admission queueing is separate from reservation
|
|
144
|
+
Admission queueing is separate from reservation state transitions; shutdown rejects queued work with `diagnostic_server_stopping`. The eAPI adapter separates connection validation from dispatch/error handling instead of maintaining a dispatch flag. `DiagnosticExecutionError` carries a typed `not_dispatched`, `completed`, or `unknown` classification; ordinary errors and malformed acknowledgements remain uncertain.
|
|
191
145
|
|
|
192
146
|
The request, observation, and finding types are discriminated by `kind`; only `ping` is implemented. Add other real operations at this seam without exposing arbitrary command strings. A destination-based operation such as traceroute can reuse multi-destination fan-out by preparing one execution per destination, although its much longer execution bound makes large requests hard to fit in the overall deadline. Packet capture needs a separate decision about transport, privilege, visibility, asynchronous lifetime, artifacts, and sensitive data; no capture-session abstractions are fabricated now.
|
|
193
147
|
|
|
@@ -198,15 +152,13 @@ Validated against the repository's cEOS 4.34.3M lab over HTTPS eAPI:
|
|
|
198
152
|
- IPv4/IPv6 loopback, explicit source and default VRF, and measured RTTs.
|
|
199
153
|
- Explicit one-second pacing, finite repeat count, and reply-timeout behavior.
|
|
200
154
|
- Group fan-out and 100% packet loss in the MGMT VRF.
|
|
201
|
-
- Multi-destination fan-out: six 10-packet pings from one host to its BGP peers completed in 18.6 s (about 56 s when issued as serial calls). A
|
|
155
|
+
- Multi-destination fan-out: six 10-packet pings from one host to its BGP peers completed in 18.6 s (about 56 s when issued as serial calls). A capacity sampler observed five simultaneous active reservations, and direct concurrent eAPI requests confirmed the device ran at most three commands at once.
|
|
202
156
|
- Invalid VRF and unavailable source fail without fallback.
|
|
203
157
|
- Overall HTTP cancellation can leave a short-lived device ping; observed processes exited after their finite probe sequence.
|
|
204
158
|
- MCP stdio execution loads configured defaults and returns real measurements.
|
|
205
159
|
|
|
206
160
|
Older EOS versions and physical platforms have not been qualified for this new tool; the existing read-path minimum does not establish ping compatibility.
|
|
207
161
|
|
|
208
|
-
The refactor was also checked against synthetic ledgers and release audits written by the pre-refactor code (`0e208ec`): inspection, checksum validation, exact committed retries, legacy absent RPC IDs, and remaining reservations stayed compatible. Audit snapshots use the shared reservation codec, and evidence/audit digests share the same JSON SHA-256 implementation; the serialized formats and schema versions are unchanged.
|
|
209
|
-
|
|
210
162
|
```bash
|
|
211
163
|
npm test
|
|
212
164
|
npm run typecheck
|
|
@@ -215,4 +167,4 @@ npm run build
|
|
|
215
167
|
INTEGRATION=1 npm test
|
|
216
168
|
```
|
|
217
169
|
|
|
218
|
-
Integration tests use the isolated `clab/testlab.clab.yaml` lab (admin/admin and lab-only TLS override). The read-path suite now defaults to that topology's unprefixed node names; `EOS_MCP_TEST_PREFIX=clab-testlab-` supports older prefixed deployments. All 13 read-path checks have been run alongside the ping suites, including the EOS code-1003 unconverted-command JSON-to-text read fallback; active ping still never retries. Optional `EOS_PING_TEST_HOST`, `EOS_PING_TEST_HOST_2`, and `EOS_PING_TEST_SILENT_HOST` override its device/silent-destination addresses. Unit tests additionally cover partial loss, input injection, mapped-address restrictions, fail-closed policy, invalid settings, concurrent calls, multi-destination ordering, concurrent destination dispatch, per-destination failure isolation, whole-request destination validation, multi-destination cancellation, uncertain reservations
|
|
170
|
+
Integration tests use the isolated `clab/testlab.clab.yaml` lab (admin/admin and lab-only TLS override). The read-path suite now defaults to that topology's unprefixed node names; `EOS_MCP_TEST_PREFIX=clab-testlab-` supports older prefixed deployments. All 13 read-path checks have been run alongside the ping suites, including the EOS code-1003 unconverted-command JSON-to-text read fallback; active ping still never retries. Optional `EOS_PING_TEST_HOST`, `EOS_PING_TEST_HOST_2`, and `EOS_PING_TEST_SILENT_HOST` override its device/silent-destination addresses. Unit tests additionally cover partial loss, input injection, mapped-address restrictions, fail-closed policy, invalid settings, concurrent calls, multi-destination ordering, concurrent destination dispatch, per-destination failure isolation, whole-request destination validation, multi-destination cancellation, uncertain reservations and their timed release, early release on a late confirmed response, cancellation, and response-size enforcement. Additional protocol regressions cover missing/stale IDs, invalid versions, contradictory result/error envelopes, and no retry on an uncorrelated read error. Live MCP integration checks timeout-to-uncertain visibility and runs a second server against the same inventory while the first holds an uncertain slot.
|