@aristanetworks/eos-mcp-server 0.8.1-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.
Files changed (44) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +17 -14
  3. package/dist/commands/probe.js +2 -1
  4. package/dist/commands/probe.js.map +1 -1
  5. package/dist/config/diagnostics.d.ts +5 -0
  6. package/dist/config/diagnostics.js +5 -1
  7. package/dist/config/diagnostics.js.map +1 -1
  8. package/dist/config/loadConfig.js +1 -0
  9. package/dist/config/loadConfig.js.map +1 -1
  10. package/dist/config/schema.d.ts +95 -1
  11. package/dist/config/schema.js +14 -1
  12. package/dist/config/schema.js.map +1 -1
  13. package/dist/connection/eosDeviceReader.d.ts +6 -1
  14. package/dist/connection/eosDeviceReader.js +14 -3
  15. package/dist/connection/eosDeviceReader.js.map +1 -1
  16. package/dist/diagnostics/executor.d.ts +7 -3
  17. package/dist/diagnostics/executor.js +16 -13
  18. package/dist/diagnostics/executor.js.map +1 -1
  19. package/dist/diagnostics/types.d.ts +19 -2
  20. package/dist/mcp/createServer.js +20 -3
  21. package/dist/mcp/createServer.js.map +1 -1
  22. package/dist/mcp/tools/ping.d.ts +2 -2
  23. package/dist/operations/eapiSlots.d.ts +68 -0
  24. package/dist/operations/eapiSlots.js +237 -0
  25. package/dist/operations/eapiSlots.js.map +1 -0
  26. package/dist/operations/readExecution.js +1 -1
  27. package/dist/operations/readExecution.js.map +1 -1
  28. package/dist/serverInfo/buildServerInfo.js +2 -0
  29. package/dist/serverInfo/buildServerInfo.js.map +1 -1
  30. package/dist/serverInfo/types.d.ts +2 -0
  31. package/docs/CODE_WALKTHROUGH.md +3 -3
  32. package/docs/DEMO_SKILLS_YOUTUBE.md +346 -0
  33. package/docs/DESIGN.md +3 -3
  34. package/docs/DIAGNOSTICS.md +14 -11
  35. package/docs/adr/0005-multi-destination-ping.md +4 -0
  36. package/docs/adr/0006-in-memory-timed-diagnostic-capacity.md +2 -0
  37. package/docs/adr/0007-per-device-diagnostic-concurrency.md +16 -0
  38. package/docs/adr/0008-read-only-tool-annotations.md +16 -0
  39. package/docs/adr/0009-shared-per-device-eapi-slots.md +40 -0
  40. package/docs/research/eos-linter-integration.md +70 -0
  41. package/package.json +1 -1
  42. package/dist/diagnostics/concurrency.d.ts +0 -29
  43. package/dist/diagnostics/concurrency.js +0 -115
  44. package/dist/diagnostics/concurrency.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"readExecution.js","sourceRoot":"","sources":["../../src/operations/readExecution.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"readExecution.js","sourceRoot":"","sources":["../../src/operations/readExecution.ts"],"names":[],"mappings":"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"}
@@ -26,6 +26,7 @@ export function buildServerInfo(context, diagnosticCapacity) {
26
26
  read_timeout_ms: context.config.readTimeoutMs,
27
27
  overall_operation_timeout_ms: context.config.overallOperationTimeoutMs ?? null,
28
28
  device_concurrency: context.config.deviceConcurrency,
29
+ read_fan_out: context.config.readFanOut,
29
30
  max_read_targets: context.config.maxReadTargets,
30
31
  max_show_commands_per_request: context.config.maxShowCommandsPerRequest,
31
32
  max_logging_messages_per_request: context.config.maxLoggingMessagesPerRequest,
@@ -36,6 +37,7 @@ export function buildServerInfo(context, diagnosticCapacity) {
36
37
  max_probes_per_request: context.config.diagnostics.maxProbesPerRequest,
37
38
  max_destinations_per_request: context.config.diagnostics.maxDestinationsPerRequest,
38
39
  device_concurrency: context.config.diagnostics.deviceConcurrency,
40
+ max_concurrent_diagnostics: context.config.diagnostics.maxConcurrentDiagnostics,
39
41
  ping_reply_timeout_ms: context.config.diagnostics.pingReplyTimeoutMs,
40
42
  command_timeout_ms: context.config.diagnostics.commandTimeoutMs,
41
43
  http_timeout_ms: context.config.diagnostics.httpTimeoutMs,
@@ -1 +1 @@
1
- {"version":3,"file":"buildServerInfo.js","sourceRoot":"","sources":["../../src/serverInfo/buildServerInfo.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"buildServerInfo.js","sourceRoot":"","sources":["../../src/serverInfo/buildServerInfo.ts"],"names":[],"mappings":"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"}
@@ -32,6 +32,7 @@ export interface ServerInfo {
32
32
  read_timeout_ms: number;
33
33
  overall_operation_timeout_ms: number | null;
34
34
  device_concurrency: number;
35
+ read_fan_out: number;
35
36
  max_read_targets: number;
36
37
  max_show_commands_per_request: number;
37
38
  max_logging_messages_per_request: number;
@@ -42,6 +43,7 @@ export interface ServerInfo {
42
43
  max_probes_per_request: number;
43
44
  max_destinations_per_request: number;
44
45
  device_concurrency: number;
46
+ max_concurrent_diagnostics: number;
45
47
  ping_reply_timeout_ms: number;
46
48
  command_timeout_ms: number;
47
49
  http_timeout_ms: number;
@@ -75,15 +75,15 @@ Shared type-narrowing utilities (`isObject`, `readString`, `readBoolean`, `readN
75
75
  ## Diagnostic Execution
76
76
 
77
77
  - `src/diagnostics/executor.ts`: typed diagnostic orchestration, inventory opt-in and probe-budget checks, existing result envelopes, and cancellation. One executor is created per server instance.
78
- - `src/diagnostics/concurrency.ts`: in-memory admission shared by concurrent calls in one server process. Unknown completion holds a slot for `commandTimeoutMs`, then a timer frees it; a late confirmed response frees it sooner. Shutdown rejects queued work; cancelled waiters are removed.
78
+ - `src/operations/eapiSlots.ts`: in-memory admission shared by every eAPI request in one server process. Reads and diagnostics share each device's slots; diagnostics also have a per-device share and a server-wide ceiling. `EapiDeviceReader` holds a read slot per request. Waiters are served oldest first, skipping those that cannot run yet. Unknown completion holds a slot for `commandTimeoutMs`, then a timer frees it; a late confirmed response frees it sooner. Shutdown rejects queued work; cancelled waiters are removed.
79
79
  - `src/diagnostics/eapiRunner.ts`: connection resolution followed by one text eAPI attempt in enable mode. Separate error paths distinguish local rejection before dispatch from uncertain RPC, transport, or malformed-result failures after dispatch; there is no mutable dispatch flag or retry.
80
80
  - `src/diagnostics/executionError.ts`: typed `AppError` classification (`not_dispatched`, `completed`, or `unknown`). Only explicitly settled errors permit capacity reuse; ordinary errors remain uncertain.
81
81
  - `src/diagnostics/ping.ts`: literal-address/VRF/source/count validation, finite ping command construction, and loss/RTT interpretation. A no-reply finding is not an execution failure.
82
82
  - `src/diagnostics/types.ts`: request, prepared intent, observation, and finding types discriminated by diagnostic kind, plus the `DiagnosticDeviceRunner` seam. Only ping is implemented; capture sessions are not pre-modeled.
83
83
 
84
- Diagnostic execution reuses read-operation orchestration with independent settings and global admission. Unknown completion holds capacity for the command budget; HTTP abort is not a remote kill signal. Each server-info call reads `DiagnosticExecutor.getCapacity()` afresh; the standalone CLI reports no live snapshot.
84
+ Diagnostic execution reuses read-operation orchestration with independent settings and per-device admission under a server-wide ceiling. Unknown completion holds capacity for the command budget; HTTP abort is not a remote kill signal. Each server-info call reads `DiagnosticExecutor.getCapacity()` afresh; the standalone CLI reports no live snapshot.
85
85
 
86
- Capacity lives in memory per server process, so several servers can run against one inventory. See [DIAGNOSTICS.md](DIAGNOSTICS.md) and [ADR 0006](adr/0006-in-memory-timed-diagnostic-capacity.md).
86
+ Capacity lives in memory per server process, so several servers can run against one inventory. See [DIAGNOSTICS.md](DIAGNOSTICS.md) [ADR 0006](adr/0006-in-memory-timed-diagnostic-capacity.md), and [ADR 0007](adr/0007-per-device-diagnostic-concurrency.md).
87
87
 
88
88
  ## MCP Layer
89
89
 
@@ -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,13 +48,13 @@ 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, device concurrency, target-count, command-count, logging-message, and response-size limits. The overall timeout aborts in-flight requests and halts further scheduling. Device HTTP responses and final serialized tool results are size-limited.
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, per-server device concurrency 5, 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.
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; 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. See [DIAGNOSTICS.md](DIAGNOSTICS.md) for the full lifecycle assumptions and limits.
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
 
@@ -58,7 +58,8 @@ diagnostics:
58
58
  maxPingCount: 10
59
59
  maxProbesPerRequest: 100
60
60
  maxDestinationsPerRequest: 16
61
- deviceConcurrency: 5
61
+ deviceConcurrency: 2
62
+ maxConcurrentDiagnostics: 32
62
63
  pingReplyTimeoutMs: 1000
63
64
  commandTimeoutMs: 30000
64
65
  httpTimeoutMs: 35000
@@ -72,14 +73,15 @@ diagnostics:
72
73
  | `maxPingCount` | Maximum probes per device and destination |
73
74
  | `maxProbesPerRequest` | Maximum resolved host count × destination count × requested probes |
74
75
  | `maxDestinationsPerRequest` | Maximum destinations in one `eos_ping` call |
75
- | `deviceConcurrency` | Diagnostic capacity of one server process, shared by its active and uncertain executions across calls |
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 |
76
78
  | `pingReplyTimeoutMs` | EOS per-reply timeout; a positive multiple of 1000 ms |
77
79
  | `commandTimeoutMs` | Conservative device execution budget; see lifecycle below |
78
80
  | `httpTimeoutMs` | Per-device diagnostic eAPI HTTP timeout, separate from `readTimeoutMs` |
79
- | `overallOperationTimeoutMs` | Whole diagnostic call deadline, including waiting for global capacity |
81
+ | `overallOperationTimeoutMs` | Whole diagnostic call deadline, including waiting for per-device and server-wide capacity |
80
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 |
81
83
 
82
- 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`. 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).
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).
83
85
 
84
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`.
85
87
 
@@ -97,21 +99,22 @@ Each host/destination execution is one text-mode eAPI request containing `enable
97
99
 
98
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).
99
101
 
100
- One admission controller is shared by all diagnostic calls in a server process. 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.
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.
101
103
 
102
- A request fans out into one execution per resolved host and destination. Executions run concurrently, up to `deviceConcurrency`, through the same admission controller as every other call; each takes and releases its own reservation exactly as a single ping does. Executions are scheduled host by host, in destination order. Queued executions wait for capacity inside the same overall deadline, so size multi-destination requests so that roughly `ceil(executions / available capacity)` successive waves of pings fit within `overallOperationTimeoutMs`; uncertain reservations reduce available capacity. The device can also limit overlap: on cEOS 4.34.3M, eAPI executed at most three commands concurrently per device, and further delivered requests waited on the device while holding their server reservations. A single-host request therefore gains at most that device's eAPI concurrency, even when more server capacity is free.
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.
103
105
 
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 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.
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
110
  `eos_get_server_info` returns a fresh `diagnostics.capacity` snapshot for that server process with:
109
111
 
110
- - `limit` and `available_count`.
111
- - `active_count`, `uncertain_count`, and `queued_count`.
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`).
112
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.
113
116
 
114
- Uncertain slots count against `deviceConcurrency` like active ones. New work 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`. If some capacity remains, diagnostics keep running without waiting for uncertain slots.
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.
115
118
 
116
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.
117
120
 
@@ -134,7 +137,7 @@ Execution `status: "success"` means ping executed and its output was understood.
134
137
 
135
138
  ## Extension seam
136
139
 
137
- `DiagnosticExecutor.execute` accepts typed diagnostic intent and owns authorization, aggregate budgets, fan-out, fail-closed global 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.
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.
138
141
 
139
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.
140
143
 
@@ -1,5 +1,9 @@
1
1
  # Accept multiple destinations in one ping request
2
2
 
3
+ Tool-annotation reasoning superseded by [ADR 0008](0008-read-only-tool-annotations.md): every tool, including ping, now advertises `readOnlyHint: true`.
4
+
5
+ Admission limits refined by [ADR 0007](0007-per-device-diagnostic-concurrency.md): executions now share a per-device limit under a server-wide ceiling instead of one process-wide `deviceConcurrency`.
6
+
3
7
  Testing several destinations from the same target, such as every BGP peer of a switch, required one `eos_ping` call per destination. MCP clients do not reliably run those calls concurrently: measured on 2026-10-28, Claude Code dispatched six pings issued in one turn strictly one at a time, and Codex runs MCP calls serially unless the server connection opts into parallel calls. Labelling ping read-only to change client scheduling would misstate an active diagnostic that generates traffic and writes durable reservations. Instead, `eos_ping` takes `destinations` (one or more unique IP literals) and runs one execution per resolved host and destination concurrently inside the server, so every client gets the same behavior from one call.
4
8
 
5
9
  Make this a breaking change rather than adding a second tool or an optional alias: one interface serves a single ping (a one-element array) and a sweep, and responses always contain one result per host and destination, each naming its destination. The removed `destination` field is rejected with guidance instead of being silently accepted. `summary` counts host/destination executions; `resolved_devices` still lists hosts.
@@ -1,5 +1,7 @@
1
1
  # Replace the durable diagnostic ledger with in-memory, time-bounded capacity
2
2
 
3
+ Admission limits refined by [ADR 0007](0007-per-device-diagnostic-concurrency.md): `deviceConcurrency` now applies per device, under a new server-wide `maxConcurrentDiagnostics`.
4
+
3
5
  Supersedes [ADR 0002](0002-fail-closed-diagnostic-reservations.md), [ADR 0003](0003-durable-diagnostic-ledger.md) and [ADR 0004](0004-offline-operator-attested-release.md). [ADR 0001](0001-non-configuring-diagnostics.md) and [ADR 0005](0005-multi-destination-ping.md) stay in force.
4
6
 
5
7
  ADRs 0002 to 0004 held an execution's slot forever when its completion was unknown, because a delivered eAPI request might in principle sit in an EOS queue and start later. Holding slots forever then required a durable SQLite ledger so restarts could not reset them, an exclusive ownership lock so a second process could not allocate fresh capacity, and an offline operator attestation and audit workflow to recover stuck slots. The exclusive lock was taken at server start whenever any host allowed diagnostics, so only one MCP server per inventory could run. A second chat session, or the desktop app alongside a Code session, failed to start at all, losing every read-only tool as well as `eos_ping`.
@@ -0,0 +1,16 @@
1
+ # Limit diagnostic concurrency per device, under a server-wide ceiling
2
+
3
+ Refined by [ADR 0009](0009-shared-per-device-eapi-slots.md): reads now share each device's slots, the top-level `deviceConcurrency` (default 3) is the per-device total, and `diagnostics.deviceConcurrency` (default 2) is the diagnostic share.
4
+
5
+ Refines the admission limit of [ADR 0005](0005-multi-destination-ping.md) and [ADR 0006](0006-in-memory-timed-diagnostic-capacity.md). Their reservation lifecycle, uncertain-slot hold, and no-retry rules are unchanged.
6
+
7
+ Until now `diagnostics.deviceConcurrency` (default 5) was one first-come pool for the whole server process; despite its name it did not know which device a slot belonged to. Measured on 2026-10-29 against the cEOS 4.34.3M lab, that made a VTEP full mesh (six hosts, five destinations each, one call per host from six concurrent subagents) take turns: each call took all five slots, but the device ran only three pings at a time. Six direct concurrent eAPI pings to one device finished as three at about 2.1 s and three at about 4.3 s. The two extra slots per call sat queued on the device while idle devices waited for capacity, so calls finished one after another about 2 s apart. The single pool also let one unhealthy device block every other: a few uncertain slots on it held the whole server's capacity for `commandTimeoutMs`.
8
+
9
+ Admission now has two limits. `diagnostics.deviceConcurrency` (default 3, the measured cEOS eAPI concurrency) caps the slots one inventory host may hold. `diagnostics.maxConcurrentDiagnostics` (default 32) caps the slots of the whole server process; `deviceConcurrency` must not exceed it. A slot is granted only while both have room. Waiters are served oldest first, skipping any whose device is still full, so a ping queued for a busy device never holds up a later ping to a free one. Uncertain slots count against their own device and the server-wide ceiling, so an unhealthy device mostly blocks itself. A request queues all its executions with the controller at once rather than through a per-call worker pool, because a host-ordered pool would wait on the first host's queue while later hosts sat idle. `maxProbesPerRequest` still bounds how many executions one request creates.
10
+
11
+ Accepted consequences:
12
+
13
+ - **Breaking:** an existing `deviceConcurrency` setting keeps its value but now applies per device. A configuration that relied on it to cap the whole server must also set `maxConcurrentDiagnostics`.
14
+ - Load on any one device from one server process drops from five to three concurrent pings by default, while total load across devices can rise to 32. N concurrent server processes can still run N times these limits.
15
+ - The capacity snapshot's top-level counts stay server-wide. It adds `device_limit` and a `devices` breakdown (available, active, uncertain and queued slots for each host holding or awaiting a slot); server info adds `limits.diagnostics.max_concurrent_diagnostics`.
16
+ - The default of 3 matches cEOS 4.34.3M only. Physical platforms may run more or fewer eAPI commands concurrently; extra slots beyond a device's own limit only queue on the device while holding a reservation.
@@ -0,0 +1,16 @@
1
+ # Advertise every tool, including ping, as read-only to MCP clients
2
+
3
+ Supersedes the tool-annotation reasoning of [ADR 0005](0005-multi-destination-ping.md). Its multi-destination request shape is unchanged.
4
+
5
+ MCP clients decide from tool annotations whether independent calls may run at the same time. Codex 0.165.0 runs MCP calls concurrently only when the server connection sets `supports_parallel_tool_calls` or the tool advertises `readOnlyHint: true`. Claude Code runs only read-only MCP tools concurrently with each other and has no per-server opt-in; measured on 2026-10-28, six unannotated pings issued in one turn ran strictly one at a time, and overlapping them took one subagent per call. No EOS tool advertised annotations, so show commands were serialized as well as pings.
6
+
7
+ ADR 0005 declined `readOnlyHint` on `eos_ping` because ping generates traffic and wrote durable reservations. [ADR 0006](0006-in-memory-timed-diagnostic-capacity.md) removed the durable ledger, so ping now writes nothing that outlives the server process. The MCP specification defines `readOnlyHint` as "does not modify its environment." Ping changes no configuration, routing, or other persistent device state; its residue is transient neighbor-cache entries and counters, the same kind of effect a show command leaves in eAPI counters and AAA accounting. Generating bounded probe traffic is observation of the network, not modification of it. [ADR 0001](0001-non-configuring-diagnostics.md) still holds that non-configuring diagnostics are not harmless reads, but annotations are advisory hints that the specification tells clients not to trust for safety; the real controls for diagnostics are server-side and apply regardless of how a client schedules calls.
8
+
9
+ Every tool now advertises `readOnlyHint: true`. `eos_ping` also advertises `openWorldHint: true`, because its destinations need not be in inventory; the other tools advertise `openWorldHint: false`, because they only reach inventory devices. `destructiveHint` and `idempotentHint` are omitted, since clients ignore them for read-only tools.
10
+
11
+ Accepted consequences:
12
+
13
+ - Clients may run several pings, or pings alongside show commands, at once. Inventory diagnostic authorization, packet and destination bounds, per-device and server-wide concurrency ([ADR 0007](0007-per-device-diagnostic-concurrency.md)), and the overall timeout still apply. Concurrent calls that exceed a device's limit queue inside their overall deadline and can time out rather than fail fast.
14
+ - Read tools (show, logging, facts, running config, probe) have only their per-call limits: the top-level `deviceConcurrency` bounds fan-out within one call, but nothing bounds load on a device across concurrent read calls. Read-only eAPI commands are cheap compared with ping, so this is accepted for now; a cross-call read limiter would be a separate decision. [ADR 0009](0009-shared-per-device-eapi-slots.md) since makes reads share each device's slots with diagnostics.
15
+ - Some clients may also use `readOnlyHint` to relax confirmation prompts, so a user may be asked less often before a ping runs. Ping still requires `mcp_diagnostics_allowed: true` in inventory.
16
+ - A future diagnostic that does change device state or exposes sensitive data, such as packet capture, must not inherit this annotation without its own decision.