@aristanetworks/eos-mcp-server 0.6.1-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +56 -0
- package/LICENSE +203 -0
- package/README.md +652 -0
- package/dist/cli.d.ts +16 -0
- package/dist/cli.js +188 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/printServerInfo.d.ts +2 -0
- package/dist/commands/printServerInfo.js +14 -0
- package/dist/commands/printServerInfo.js.map +1 -0
- package/dist/commands/probe.d.ts +2 -0
- package/dist/commands/probe.js +26 -0
- package/dist/commands/probe.js.map +1 -0
- package/dist/commands/validateInventory.d.ts +9 -0
- package/dist/commands/validateInventory.js +59 -0
- package/dist/commands/validateInventory.js.map +1 -0
- package/dist/config/loadConfig.d.ts +3 -0
- package/dist/config/loadConfig.js +84 -0
- package/dist/config/loadConfig.js.map +1 -0
- package/dist/config/schema.d.ts +151 -0
- package/dist/config/schema.js +54 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/configuration/getRunningConfig.d.ts +24 -0
- package/dist/configuration/getRunningConfig.js +38 -0
- package/dist/configuration/getRunningConfig.js.map +1 -0
- package/dist/connection/eosDeviceReader.d.ts +18 -0
- package/dist/connection/eosDeviceReader.js +13 -0
- package/dist/connection/eosDeviceReader.js.map +1 -0
- package/dist/connection/resolveConnection.d.ts +4 -0
- package/dist/connection/resolveConnection.js +58 -0
- package/dist/connection/resolveConnection.js.map +1 -0
- package/dist/connection/validateStartupConnections.d.ts +4 -0
- package/dist/connection/validateStartupConnections.js +28 -0
- package/dist/connection/validateStartupConnections.js.map +1 -0
- package/dist/core/errors.d.ts +8 -0
- package/dist/core/errors.js +22 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/version.d.ts +2 -0
- package/dist/core/version.js +7 -0
- package/dist/core/version.js.map +1 -0
- package/dist/eapi/client.d.ts +8 -0
- package/dist/eapi/client.js +159 -0
- package/dist/eapi/client.js.map +1 -0
- package/dist/eapi/commands.d.ts +2 -0
- package/dist/eapi/commands.js +25 -0
- package/dist/eapi/commands.js.map +1 -0
- package/dist/eapi/transport.d.ts +21 -0
- package/dist/eapi/transport.js +143 -0
- package/dist/eapi/transport.js.map +1 -0
- package/dist/eapi/types.d.ts +49 -0
- package/dist/eapi/types.js +15 -0
- package/dist/eapi/types.js.map +1 -0
- package/dist/facts/getFacts.d.ts +33 -0
- package/dist/facts/getFacts.js +50 -0
- package/dist/facts/getFacts.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +66 -0
- package/dist/index.js.map +1 -0
- package/dist/inventory/buildModel.d.ts +3 -0
- package/dist/inventory/buildModel.js +79 -0
- package/dist/inventory/buildModel.js.map +1 -0
- package/dist/inventory/effectiveVars.d.ts +2 -0
- package/dist/inventory/effectiveVars.js +52 -0
- package/dist/inventory/effectiveVars.js.map +1 -0
- package/dist/inventory/graph.d.ts +6 -0
- package/dist/inventory/graph.js +81 -0
- package/dist/inventory/graph.js.map +1 -0
- package/dist/inventory/internalTypes.d.ts +17 -0
- package/dist/inventory/internalTypes.js +2 -0
- package/dist/inventory/internalTypes.js.map +1 -0
- package/dist/inventory/internalUtils.d.ts +10 -0
- package/dist/inventory/internalUtils.js +68 -0
- package/dist/inventory/internalUtils.js.map +1 -0
- package/dist/inventory/listInventoryView.d.ts +23 -0
- package/dist/inventory/listInventoryView.js +22 -0
- package/dist/inventory/listInventoryView.js.map +1 -0
- package/dist/inventory/loadInventory.d.ts +4 -0
- package/dist/inventory/loadInventory.js +87 -0
- package/dist/inventory/loadInventory.js.map +1 -0
- package/dist/inventory/normalize.d.ts +4 -0
- package/dist/inventory/normalize.js +251 -0
- package/dist/inventory/normalize.js.map +1 -0
- package/dist/inventory/parse.d.ts +6 -0
- package/dist/inventory/parse.js +31 -0
- package/dist/inventory/parse.js.map +1 -0
- package/dist/inventory/policy.d.ts +11 -0
- package/dist/inventory/policy.js +27 -0
- package/dist/inventory/policy.js.map +1 -0
- package/dist/inventory/resolveTarget.d.ts +14 -0
- package/dist/inventory/resolveTarget.js +55 -0
- package/dist/inventory/resolveTarget.js.map +1 -0
- package/dist/inventory/types.d.ts +50 -0
- package/dist/inventory/types.js +2 -0
- package/dist/inventory/types.js.map +1 -0
- package/dist/inventory/validateNormalized.d.ts +2 -0
- package/dist/inventory/validateNormalized.js +64 -0
- package/dist/inventory/validateNormalized.js.map +1 -0
- package/dist/inventory/varValidation.d.ts +2 -0
- package/dist/inventory/varValidation.js +60 -0
- package/dist/inventory/varValidation.js.map +1 -0
- package/dist/inventory/writePolicy.d.ts +2 -0
- package/dist/inventory/writePolicy.js +36 -0
- package/dist/inventory/writePolicy.js.map +1 -0
- package/dist/logging/loggingQuery.d.ts +15 -0
- package/dist/logging/loggingQuery.js +38 -0
- package/dist/logging/loggingQuery.js.map +1 -0
- package/dist/logging/showLogging.d.ts +28 -0
- package/dist/logging/showLogging.js +37 -0
- package/dist/logging/showLogging.js.map +1 -0
- package/dist/mcp/createServer.d.ts +3 -0
- package/dist/mcp/createServer.js +82 -0
- package/dist/mcp/createServer.js.map +1 -0
- package/dist/mcp/toolResult.d.ts +7 -0
- package/dist/mcp/toolResult.js +13 -0
- package/dist/mcp/toolResult.js.map +1 -0
- package/dist/mcp/tools/getFacts.d.ts +21 -0
- package/dist/mcp/tools/getFacts.js +17 -0
- package/dist/mcp/tools/getFacts.js.map +1 -0
- package/dist/mcp/tools/getRunningConfig.d.ts +21 -0
- package/dist/mcp/tools/getRunningConfig.js +17 -0
- package/dist/mcp/tools/getRunningConfig.js.map +1 -0
- package/dist/mcp/tools/getServerInfo.d.ts +10 -0
- package/dist/mcp/tools/getServerInfo.js +9 -0
- package/dist/mcp/tools/getServerInfo.js.map +1 -0
- package/dist/mcp/tools/listInventory.d.ts +16 -0
- package/dist/mcp/tools/listInventory.js +15 -0
- package/dist/mcp/tools/listInventory.js.map +1 -0
- package/dist/mcp/tools/probeDevices.d.ts +21 -0
- package/dist/mcp/tools/probeDevices.js +14 -0
- package/dist/mcp/tools/probeDevices.js.map +1 -0
- package/dist/mcp/tools/runShow.d.ts +30 -0
- package/dist/mcp/tools/runShow.js +34 -0
- package/dist/mcp/tools/runShow.js.map +1 -0
- package/dist/mcp/tools/showLogging.d.ts +24 -0
- package/dist/mcp/tools/showLogging.js +20 -0
- package/dist/mcp/tools/showLogging.js.map +1 -0
- package/dist/operations/readExecution.d.ts +57 -0
- package/dist/operations/readExecution.js +132 -0
- package/dist/operations/readExecution.js.map +1 -0
- package/dist/probe/probeDevices.d.ts +24 -0
- package/dist/probe/probeDevices.js +24 -0
- package/dist/probe/probeDevices.js.map +1 -0
- package/dist/serverInfo/buildServerInfo.d.ts +2 -0
- package/dist/serverInfo/buildServerInfo.js +49 -0
- package/dist/serverInfo/buildServerInfo.js.map +1 -0
- package/dist/serverInfo/types.d.ts +46 -0
- package/dist/serverInfo/types.js +2 -0
- package/dist/serverInfo/types.js.map +1 -0
- package/dist/show/runShow.d.ts +29 -0
- package/dist/show/runShow.js +40 -0
- package/dist/show/runShow.js.map +1 -0
- package/dist/utils/json.d.ts +1 -0
- package/dist/utils/json.js +4 -0
- package/dist/utils/json.js.map +1 -0
- package/dist/utils/path.d.ts +2 -0
- package/dist/utils/path.js +14 -0
- package/dist/utils/path.js.map +1 -0
- package/dist/utils/value.d.ts +6 -0
- package/dist/utils/value.js +28 -0
- package/dist/utils/value.js.map +1 -0
- package/docs/CHECKPOINT.md +46 -0
- package/docs/CODE_WALKTHROUGH.md +112 -0
- package/docs/DESIGN.md +56 -0
- package/docs/DEVELOPMENT.md +72 -0
- package/docs/EXAMPLES.md +178 -0
- package/docs/IMPLEMENTATION_PLAN.md +32 -0
- package/docs/QUICKSTART.md +152 -0
- package/example-inventories/canonical-fabric.yaml +45 -0
- package/example-inventories/multi-password.yaml +35 -0
- package/example-inventories/simplified-lab.yaml +33 -0
- package/package.json +57 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ResolvedServerConfig } from "../config/schema.js";
|
|
2
|
+
import type { EosCommandResult } from "../eapi/types.js";
|
|
3
|
+
import type { EosDeviceReader } from "../connection/eosDeviceReader.js";
|
|
4
|
+
import type { InventoryModel } from "../inventory/types.js";
|
|
5
|
+
import { type DeviceResultSummary } from "../operations/readExecution.js";
|
|
6
|
+
export interface RunShowOptions {
|
|
7
|
+
target: string;
|
|
8
|
+
commands: string[];
|
|
9
|
+
outputFormat: "auto" | "json" | "text";
|
|
10
|
+
includeRaw?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export type NormalizedCommandResult = EosCommandResult;
|
|
13
|
+
export interface RunShowResult {
|
|
14
|
+
target: string;
|
|
15
|
+
target_type: "host" | "group";
|
|
16
|
+
requested_output_format: "auto" | "json" | "text";
|
|
17
|
+
resolved_devices: string[];
|
|
18
|
+
summary: DeviceResultSummary;
|
|
19
|
+
results: Array<{
|
|
20
|
+
inventory_hostname: string;
|
|
21
|
+
resolved_endpoint: string;
|
|
22
|
+
status: "success" | "failed";
|
|
23
|
+
actual_output_format?: "json" | "text";
|
|
24
|
+
command_results?: NormalizedCommandResult[];
|
|
25
|
+
error_code?: string;
|
|
26
|
+
message?: string;
|
|
27
|
+
}>;
|
|
28
|
+
}
|
|
29
|
+
export declare function runShow(model: InventoryModel, config: ResolvedServerConfig, options: RunShowOptions, reader: EosDeviceReader): Promise<RunShowResult>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { AppError } from "../core/errors.js";
|
|
2
|
+
import { normalizeShowCommand } from "../eapi/commands.js";
|
|
3
|
+
import { buildReadDeviceFailure, buildReadDeviceSuccess, buildReadOperationResultEnvelope, enforceShowCommandLimit, executeReadOperation } from "../operations/readExecution.js";
|
|
4
|
+
export async function runShow(model, config, options, reader) {
|
|
5
|
+
const commands = normalizeShowCommands(options.commands);
|
|
6
|
+
enforceShowCommandLimit(config, commands.length);
|
|
7
|
+
const operation = await executeReadOperation(model, config, {
|
|
8
|
+
target: options.target,
|
|
9
|
+
operationName: "eos_run_show",
|
|
10
|
+
run: async (host, signal) => {
|
|
11
|
+
const commandResults = await reader.runShowCommands(host, commands, options.outputFormat, {
|
|
12
|
+
signal,
|
|
13
|
+
includeRawEntries: options.includeRaw === true
|
|
14
|
+
});
|
|
15
|
+
const firstResult = commandResults[0];
|
|
16
|
+
return buildReadDeviceSuccess(host, {
|
|
17
|
+
actual_output_format: firstResult?.output_format ?? "json",
|
|
18
|
+
command_results: commandResults
|
|
19
|
+
});
|
|
20
|
+
},
|
|
21
|
+
onError: (host, error) => buildReadDeviceFailure(host, "show_command_failed", error)
|
|
22
|
+
});
|
|
23
|
+
return buildReadOperationResultEnvelope(options.target, operation, {
|
|
24
|
+
extra: {
|
|
25
|
+
requested_output_format: options.outputFormat
|
|
26
|
+
},
|
|
27
|
+
responseSizeLimit: {
|
|
28
|
+
config,
|
|
29
|
+
operationName: "eos_run_show",
|
|
30
|
+
narrowingGuidance: "Reduce the number of target devices, use fewer commands per request, or request text format for more concise output."
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
function normalizeShowCommands(commands) {
|
|
35
|
+
if (commands.length === 0) {
|
|
36
|
+
throw new AppError("show_commands_missing", "runShow requires at least one command");
|
|
37
|
+
}
|
|
38
|
+
return commands.map((command) => normalizeShowCommand(command));
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=runShow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runShow.js","sourceRoot":"","sources":["../../src/show/runShow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAI3D,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,gCAAgC,EAChC,uBAAuB,EACvB,oBAAoB,EAErB,MAAM,gCAAgC,CAAC;AA4BxC,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,KAAqB,EACrB,MAA4B,EAC5B,OAAuB,EACvB,MAAuB;IAEvB,MAAM,QAAQ,GAAG,qBAAqB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACzD,uBAAuB,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAEjD,MAAM,SAAS,GAAG,MAAM,oBAAoB,CAAmC,KAAK,EAAE,MAAM,EAAE;QAC5F,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,aAAa,EAAE,cAAc;QAC7B,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE;YAC1B,MAAM,cAAc,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,YAAY,EAAE;gBACxF,MAAM;gBACN,iBAAiB,EAAE,OAAO,CAAC,UAAU,KAAK,IAAI;aAC/C,CAAC,CAAC;YACH,MAAM,WAAW,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;YAEtC,OAAO,sBAAsB,CAAC,IAAI,EAAE;gBAClC,oBAAoB,EAAE,WAAW,EAAE,aAAa,IAAI,MAAM;gBAC1D,eAAe,EAAE,cAAc;aAChC,CAAC,CAAC;QACL,CAAC;QACD,OAAO,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,sBAAsB,CAAC,IAAI,EAAE,qBAAqB,EAAE,KAAK,CAAC;KACrF,CAAC,CAAC;IAEH,OAAO,gCAAgC,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE;QACjE,KAAK,EAAE;YACL,uBAAuB,EAAE,OAAO,CAAC,YAAY;SAC9C;QACD,iBAAiB,EAAE;YACjB,MAAM;YACN,aAAa,EAAE,cAAc;YAC7B,iBAAiB,EAAE,sHAAsH;SAC1I;KACF,CAAC,CAAC;AACL,CAAC;AAED,SAAS,qBAAqB,CAAC,QAAkB;IAC/C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,QAAQ,CAAC,uBAAuB,EAAE,uCAAuC,CAAC,CAAC;IACvF,CAAC;IAED,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC,CAAC;AAClE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function prettyJson(value: unknown): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/utils/json.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
export function resolvePathFromConfig(configPath, value) {
|
|
3
|
+
if (path.isAbsolute(value)) {
|
|
4
|
+
return value;
|
|
5
|
+
}
|
|
6
|
+
return path.resolve(path.dirname(configPath), value);
|
|
7
|
+
}
|
|
8
|
+
export function resolvePathFromCwd(value) {
|
|
9
|
+
if (path.isAbsolute(value)) {
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
return path.resolve(process.cwd(), value);
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=path.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path.js","sourceRoot":"","sources":["../../src/utils/path.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,UAAU,qBAAqB,CAAC,UAAkB,EAAE,KAAa;IACrE,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,KAAa;IAC9C,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare function readString(value: unknown): string | undefined;
|
|
2
|
+
export declare function readNonEmptyString(value: unknown): string | undefined;
|
|
3
|
+
export declare function readBoolean(value: unknown): boolean | undefined;
|
|
4
|
+
export declare function readNumber(value: unknown): number | undefined;
|
|
5
|
+
export declare function readPositiveInteger(value: unknown): number | undefined;
|
|
6
|
+
export declare function isObject(value: unknown): value is Record<string, unknown>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export function readString(value) {
|
|
2
|
+
return typeof value === "string" ? value : undefined;
|
|
3
|
+
}
|
|
4
|
+
export function readNonEmptyString(value) {
|
|
5
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
6
|
+
}
|
|
7
|
+
export function readBoolean(value) {
|
|
8
|
+
return typeof value === "boolean" ? value : undefined;
|
|
9
|
+
}
|
|
10
|
+
export function readNumber(value) {
|
|
11
|
+
return typeof value === "number" ? value : undefined;
|
|
12
|
+
}
|
|
13
|
+
export function readPositiveInteger(value) {
|
|
14
|
+
if (typeof value === "number" && Number.isInteger(value) && value > 0) {
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
if (typeof value === "string" && value.length > 0) {
|
|
18
|
+
const parsed = Number(value);
|
|
19
|
+
if (Number.isInteger(parsed) && parsed > 0) {
|
|
20
|
+
return parsed;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
export function isObject(value) {
|
|
26
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=value.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"value.js","sourceRoot":"","sources":["../../src/utils/value.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,KAAc;IAC/C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,OAAO,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACxD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,KAAc;IAChD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACtE,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClD,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC7B,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3C,OAAO,MAAM,CAAC;QAChB,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,KAAc;IACrC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# EOS MCP Server Checkpoint
|
|
2
|
+
|
|
3
|
+
## Current state
|
|
4
|
+
|
|
5
|
+
The server is a test-backed, read-only MCP service for Arista EOS eAPI. The product boundary is permanent: configuration-changing operations are outside the implementation and specification.
|
|
6
|
+
|
|
7
|
+
## Implemented surface
|
|
8
|
+
|
|
9
|
+
### MCP tools
|
|
10
|
+
|
|
11
|
+
- `eos_get_server_info`
|
|
12
|
+
- `eos_list_inventory`
|
|
13
|
+
- `eos_probe_devices`
|
|
14
|
+
- `eos_run_show`
|
|
15
|
+
- `eos_show_logging`
|
|
16
|
+
- `eos_get_facts`
|
|
17
|
+
- `eos_get_running_config`
|
|
18
|
+
|
|
19
|
+
### Local commands
|
|
20
|
+
|
|
21
|
+
- `serve`
|
|
22
|
+
- `validate-inventory`
|
|
23
|
+
- `print-server-info`
|
|
24
|
+
- `probe`
|
|
25
|
+
|
|
26
|
+
## Safety and operational controls
|
|
27
|
+
|
|
28
|
+
- Inventory-only host and group targeting.
|
|
29
|
+
- Explicit EOS eligibility and inherited read-policy enforcement.
|
|
30
|
+
- Fail-closed groups containing ineligible or read-denied hosts.
|
|
31
|
+
- Strict password-source and environment-prefix checks.
|
|
32
|
+
- HTTPS with certificate validation by default and optional custom CA support.
|
|
33
|
+
- Validated show commands and bounded logging/running-configuration queries.
|
|
34
|
+
- Read-operation concurrency, target, response-size, and timeout controls.
|
|
35
|
+
- Sanitized result envelopes with stable machine-readable errors.
|
|
36
|
+
|
|
37
|
+
## Re-entry reading
|
|
38
|
+
|
|
39
|
+
1. [`README.md`](../README.md) for operator usage.
|
|
40
|
+
2. [`docs/DESIGN.md`](DESIGN.md) for the authoritative specification.
|
|
41
|
+
3. [`docs/CODE_WALKTHROUGH.md`](CODE_WALKTHROUGH.md) for source navigation.
|
|
42
|
+
4. [`src/operations/readExecution.ts`](../src/operations/readExecution.ts) for shared device operation controls.
|
|
43
|
+
|
|
44
|
+
## Validation
|
|
45
|
+
|
|
46
|
+
Run `npm test`, `npm run typecheck`, and `npm run build` after changes. Optional integration tests require the configured cEOS environment.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Code Walkthrough
|
|
2
|
+
|
|
3
|
+
## Top Level
|
|
4
|
+
|
|
5
|
+
This repository is a single TypeScript/Node package.
|
|
6
|
+
|
|
7
|
+
- `src/` contains all source code.
|
|
8
|
+
- `test/` contains Vitest tests.
|
|
9
|
+
- `dist/` is generated build output from `tsc`.
|
|
10
|
+
- `docs/` contains project documentation (design, checkpoint, implementation plan, etc.).
|
|
11
|
+
- `Makefile` wraps build, lint/static policy checks, test, typecheck, clean, and packaging.
|
|
12
|
+
- `package.json` defines scripts: `npm test`, `npm run typecheck`, `npm run lint`, and `npm run build`. The package `prepack` hook runs `npm run build`.
|
|
13
|
+
- `scripts/static-policy.mjs` performs lightweight source policy checks for banned patterns such as plain `throw new Error`, `@ts-ignore`, `eslint-disable`, and `as any`.
|
|
14
|
+
|
|
15
|
+
## Runtime Entry
|
|
16
|
+
|
|
17
|
+
Execution starts at `src/index.ts`. It parses CLI args, loads config, then dispatches one of four commands:
|
|
18
|
+
|
|
19
|
+
- `serve`: load inventory, validate startup credentials, start MCP stdio server.
|
|
20
|
+
- `validate-inventory`: validate inventory and print the result.
|
|
21
|
+
- `print-server-info`: print sanitized server metadata.
|
|
22
|
+
- `probe`: run the same probe logic as the MCP probe tool.
|
|
23
|
+
|
|
24
|
+
CLI parsing lives in `src/cli.ts`. The app name and version are read from `package.json` at runtime via `src/core/version.ts`. Shared error handling lives in `src/core/errors.ts`, which defines `AppError` and the stable machine-readable error codes used across the CLI and MCP layers.
|
|
25
|
+
|
|
26
|
+
## Config And Inventory
|
|
27
|
+
|
|
28
|
+
Config loading is in `src/config/loadConfig.ts`, with Zod schemas in `src/config/schema.ts`. It merges optional config-file values with CLI overrides and resolves paths.
|
|
29
|
+
|
|
30
|
+
`src/inventory/loadInventory.ts` orchestrates inventory loading. It supports simplified YAML and canonical Ansible-style YAML by delegating to a pipeline: parsing (`src/inventory/parse.ts`), schema detection and normalization (`src/inventory/normalize.ts`), structural and variable-type validation (`src/inventory/validateNormalized.ts`, `src/inventory/varValidation.ts`), and model construction (`src/inventory/buildModel.ts`). Together these validate structure, build effective host vars, resolve groups, and produce an `InventoryModel`.
|
|
31
|
+
|
|
32
|
+
Supporting inventory modules:
|
|
33
|
+
|
|
34
|
+
- `src/inventory/types.ts`: public inventory model types.
|
|
35
|
+
- `src/inventory/internalTypes.ts` / `src/inventory/internalUtils.ts`: shared types and helpers used across the parsing/normalization/validation pipeline.
|
|
36
|
+
- `src/inventory/effectiveVars.ts`: global/group/host variable inheritance and same-depth conflict handling.
|
|
37
|
+
- `src/inventory/graph.ts`: group parent maps, group depths, host lineage, direct memberships, and resolved group hosts.
|
|
38
|
+
- `src/inventory/policy.ts`: EOS eligibility and read access evaluation, including the `mcp_read_allowed` fail-closed check.
|
|
39
|
+
- `src/inventory/resolveTarget.ts`: host/group target resolution and policy fail-closed checks.
|
|
40
|
+
- `src/inventory/listInventoryView.ts`: sanitized inventory view for MCP output.
|
|
41
|
+
|
|
42
|
+
## Connection And eAPI
|
|
43
|
+
|
|
44
|
+
Connection resolution is in `src/connection/resolveConnection.ts`. It turns effective host vars plus server config into an eAPI connection: endpoint, username, password, TLS flags, CA file, timeout, eAPI output version, and response-size limit.
|
|
45
|
+
|
|
46
|
+
`src/connection/eosDeviceReader.ts` defines the host-oriented `EosDeviceReader` interface. Its `EapiDeviceReader` adapter owns per-host connection resolution and delegates command execution to the low-level eAPI runner.
|
|
47
|
+
|
|
48
|
+
Startup credential validation is in `src/connection/validateStartupConnections.ts`.
|
|
49
|
+
|
|
50
|
+
eAPI protocol and transport are split:
|
|
51
|
+
|
|
52
|
+
- `src/eapi/client.ts`: builds JSON-RPC `runCmds` requests using the connection's `eapiVersion` (`"latest"` by default, `1` when pinned in config), handles HTTP errors, invalid JSON, JSON-RPC errors, and unexpected result counts. Supports opt-in enable mode (`{ enable: true }`) for privileged commands by prepending `enable` to the wire commands and stripping the extra result entry transparently. Per-request timeout and caller cancellation are combined with `AbortSignal`.
|
|
53
|
+
- `src/eapi/transport.ts`: production HTTPS transport and test-friendly fetch transport. The production transport enforces `maxResponseSizeBytes` while chunks are received, before buffering an oversized device response.
|
|
54
|
+
- `src/eapi/types.ts`: shared eAPI types, the low-level `EosCommandRunner` interface used by `EapiDeviceReader`, `EapiCommandOptions`, and helpers for validating/drilling into eAPI JSON-RPC response payloads.
|
|
55
|
+
|
|
56
|
+
## Read Tool Services
|
|
57
|
+
|
|
58
|
+
The core read behavior is implemented as service modules:
|
|
59
|
+
|
|
60
|
+
- `src/probe/probeDevices.ts`: runs `show version` to verify readiness.
|
|
61
|
+
- `src/eapi/commands.ts`: normalizes single-line EOS command inputs, rejects risky CLI modifiers/metacharacters, and validates `show` command boundaries.
|
|
62
|
+
- `src/show/runShow.ts`: validates strict `show` commands and runs them with `auto`, `json`, or `text` behavior.
|
|
63
|
+
- `src/logging/loggingQuery.ts`: validates Log Severity and message-count inputs, applies logging defaults/limits, and builds the EOS logging command.
|
|
64
|
+
- `src/logging/showLogging.ts`: executes the bounded Logging Query and returns unparsed log text.
|
|
65
|
+
- `src/facts/getFacts.ts`: collects fixed facts from `show version`.
|
|
66
|
+
- `src/configuration/getRunningConfig.ts`: returns running config text, requiring `section` for group targets. Uses enable mode since `show running-config` requires privileged access.
|
|
67
|
+
|
|
68
|
+
All device-facing read services accept an `EosDeviceReader` (defined in `src/connection/eosDeviceReader.ts`). They provide inventory hosts and command intent; the eAPI adapter resolves each host's connection before executing commands.
|
|
69
|
+
|
|
70
|
+
Shared read orchestration lives in `src/operations/readExecution.ts`. It centralizes target resolution, target limits, concurrency, overall timeout cancellation, common per-device result fields, result summaries (including the shared `DeviceResultSummary` type used by all result interfaces), final result-envelope response-size enforcement, and per-device `AppError.code` preservation.
|
|
71
|
+
|
|
72
|
+
Shared type-narrowing utilities (`isObject`, `readString`, `readBoolean`, `readNumber`, etc.) live in `src/utils/value.ts`.
|
|
73
|
+
|
|
74
|
+
## MCP Layer
|
|
75
|
+
|
|
76
|
+
The MCP server is assembled in `src/mcp/createServer.ts`. It creates the official SDK `McpServer`, registers seven read-only tools, and connects over stdio.
|
|
77
|
+
|
|
78
|
+
Tool adapters live under `src/mcp/tools/`:
|
|
79
|
+
|
|
80
|
+
- `getServerInfo.ts`
|
|
81
|
+
- `listInventory.ts`
|
|
82
|
+
- `probeDevices.ts`
|
|
83
|
+
- `runShow.ts`
|
|
84
|
+
- `showLogging.ts`
|
|
85
|
+
- `getFacts.ts`
|
|
86
|
+
- `getRunningConfig.ts`
|
|
87
|
+
|
|
88
|
+
These adapters define Zod input schemas, call the service layer, and return both text JSON and structured MCP content.
|
|
89
|
+
|
|
90
|
+
## Server Info And Commands
|
|
91
|
+
|
|
92
|
+
Server metadata is built by `src/serverInfo/buildServerInfo.ts`, with types in `src/serverInfo/types.ts`.
|
|
93
|
+
|
|
94
|
+
Local CLI commands live in `src/commands/`:
|
|
95
|
+
|
|
96
|
+
- `validateInventory.ts`
|
|
97
|
+
- `printServerInfo.ts`
|
|
98
|
+
- `probe.ts`
|
|
99
|
+
|
|
100
|
+
## Tests
|
|
101
|
+
|
|
102
|
+
Tests mirror the source layout:
|
|
103
|
+
|
|
104
|
+
- CLI and config: `cli.test.ts`, `loadConfig.test.ts`, `validateInventoryCommand.test.ts`
|
|
105
|
+
- Inventory and target behavior: `inventory.test.ts`, `targetResolution.test.ts`
|
|
106
|
+
- eAPI and connection behavior: `eapiClient.test.ts`, `eosDeviceReader.test.ts`, `startupValidation.test.ts`, `responseSize.test.ts`
|
|
107
|
+
- Read services and orchestration: `probeDevices.test.ts`, `runShow.test.ts`, `loggingQuery.test.ts`, `showLogging.test.ts`, `getFacts.test.ts`, `getRunningConfig.test.ts`, `readExecution.test.ts`
|
|
108
|
+
- Server info and errors: `buildServerInfo.test.ts`, `errors.test.ts`, `errorTaxonomy.test.ts`
|
|
109
|
+
- MCP adapters and stdio: `readToolsMcp.test.ts`, `probeDevicesTool.test.ts`, `listInventoryTool.test.ts`, `mcpStdioSmoke.test.ts`
|
|
110
|
+
- Package/static policy: `packagePolicy.test.ts`, `packageSmoke.test.ts`
|
|
111
|
+
- Optional cEOS integration (requires a configured lab): `integration.test.ts`
|
|
112
|
+
- Shared test helpers: `test/helpers.ts`
|
package/docs/DESIGN.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# EOS MCP Server Design Specification
|
|
2
|
+
|
|
3
|
+
## Scope
|
|
4
|
+
|
|
5
|
+
EOS MCP Server is an ESM TypeScript MCP server that provides inventory-scoped, read-only access to Arista EOS devices over eAPI (HTTPS). It runs over stdio MCP transport and is permanently read-only: the implementation exposes operational inspection and diagnostics only, and never exposes configuration-changing operations.
|
|
6
|
+
|
|
7
|
+
## Tool surface
|
|
8
|
+
|
|
9
|
+
| Tool | Purpose |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| `eos_get_server_info` | Sanitized runtime, limits, and inventory summary |
|
|
12
|
+
| `eos_list_inventory` | Eligible hosts and groups |
|
|
13
|
+
| `eos_probe_devices` | Connectivity, authentication, and harmless command check |
|
|
14
|
+
| `eos_run_show` | Validated single-line `show` commands |
|
|
15
|
+
| `eos_show_logging` | Bounded logging retrieval |
|
|
16
|
+
| `eos_get_facts` | Fixed device facts |
|
|
17
|
+
| `eos_get_running_config` | Running configuration retrieval, with a required section selector for groups |
|
|
18
|
+
|
|
19
|
+
Local CLI commands provide inventory validation, server-info output, and probing.
|
|
20
|
+
|
|
21
|
+
## Target boundary
|
|
22
|
+
|
|
23
|
+
- A target is exactly one inventory host or group name.
|
|
24
|
+
- Address, hostname, pattern, and ad-hoc targets are rejected.
|
|
25
|
+
- Host and group names use `^[A-Za-z0-9_.-]+$` and cannot collide.
|
|
26
|
+
- Group hosts are deduplicated and ordered alphabetically.
|
|
27
|
+
- Canonical inventories merge repeated group declarations with host/child union and later-wins variables.
|
|
28
|
+
|
|
29
|
+
## Inventory and policy
|
|
30
|
+
|
|
31
|
+
Canonical Ansible-style YAML and simplified YAML are supported. Structural keys are strict; arbitrary variables remain permitted. EOS eligibility requires `ansible_network_os: eos` or `mcp_platform: arista_eos`; conflicting declarations fail validation.
|
|
32
|
+
|
|
33
|
+
`mcp_read_allowed` defaults to `true` for eligible EOS hosts and follows inherited inventory variable precedence. Operational requests fail closed when any resolved host is ineligible or read-denied — a mixed or ineligible target fails as a whole, and devices are never silently skipped. The inventory is the only policy source.
|
|
34
|
+
|
|
35
|
+
## Connection security
|
|
36
|
+
|
|
37
|
+
- HTTPS is required.
|
|
38
|
+
- Certificate validation defaults to enabled; inventory may set an explicit lab override and server config may provide a CA bundle.
|
|
39
|
+
- A host resolves exactly one password source: `mcp_password_env` or `ansible_password`. The environment reference is preferred and must match a configured prefix (`EOS_MCP_` by default).
|
|
40
|
+
- Startup validation verifies connection data for all eligible hosts.
|
|
41
|
+
|
|
42
|
+
## Command safety
|
|
43
|
+
|
|
44
|
+
`eos_run_show` accepts only trimmed, single-line commands beginning with `show`. It rejects control characters, shell metacharacters, and CLI output modifiers. `eos_get_running_config.section` uses the same single-line restrictions. Enable mode is used only as needed to retrieve running configuration.
|
|
45
|
+
|
|
46
|
+
## Runtime controls
|
|
47
|
+
|
|
48
|
+
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.
|
|
49
|
+
|
|
50
|
+
## Result and error model
|
|
51
|
+
|
|
52
|
+
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 diagnostic tools expose raw eAPI payloads only through an explicit `include_raw` option.
|
|
53
|
+
|
|
54
|
+
## Compatibility and validation
|
|
55
|
+
|
|
56
|
+
The read surface is validated against cEOS 4.34.3M. EOS 4.20 is the documented minimum for supported read operations. Changes must preserve strict TypeScript checks and pass the unit, stdio smoke, and package-policy test suites.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Developer workflow
|
|
2
|
+
|
|
3
|
+
This guide is for contributors and for users who need to build `eos-mcp-server` from a source checkout. For a normal installation, download a package from the [latest GitHub release](https://github.com/aristanetworks/eos-mcp-server/releases/latest) and follow the [README](../README.md).
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
- Node.js 24+
|
|
8
|
+
- npm
|
|
9
|
+
|
|
10
|
+
## Build from source
|
|
11
|
+
|
|
12
|
+
From the repository root:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install
|
|
16
|
+
make build
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Run the built CLI directly:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
node dist/index.js serve --inventory path/to/inventory.yml
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
For development without compiling first:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm run dev -- serve --inventory path/to/inventory.yml
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Make a local installation
|
|
32
|
+
|
|
33
|
+
To expose the command from a checkout:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm install
|
|
37
|
+
make build
|
|
38
|
+
npm link
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Or install the checkout directly:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm install -g /absolute/path/to/eos-mcp-server
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Remove a linked installation later with:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npm unlink -g @aristanetworks/eos-mcp-server
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Package a release artifact
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
make pack
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
This performs a clean build and produces `aristanetworks-eos-mcp-server-<version>.tgz`, which can be installed with `npm install -g ./aristanetworks-eos-mcp-server-<version>.tgz`. `npm pack` also rebuilds through the `prepack` hook.
|
|
60
|
+
|
|
61
|
+
## Publish to npm
|
|
62
|
+
|
|
63
|
+
The package is published as `@aristanetworks/eos-mcp-server`. Pushing a `v*` tag runs `.github/workflows/release.yml`, which tests, packs, publishes to npm through [trusted publishing](https://docs.npmjs.com/trusted-publishers) (OIDC, no token secret), and creates the GitHub release. Tags containing `-alpha`, `-beta`, or `-rc` publish under the `next` dist-tag; other tags publish as `latest`. Published versions carry npm provenance attestations.
|
|
64
|
+
|
|
65
|
+
## Verify changes
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
make test
|
|
69
|
+
make typecheck
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The repository's [AGENTS.md](../AGENTS.md) lists all common commands and architectural guidance.
|
package/docs/EXAMPLES.md
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# EOS MCP Server — Example Prompts
|
|
2
|
+
|
|
3
|
+
These examples show how to interact with the EOS MCP server through Claude. All examples are drawn from a real cEOSLab testlab session.
|
|
4
|
+
|
|
5
|
+
This assumes `eos-mcp-server` is already installed and you have an inventory file — see [Install and get started](../README.md#install-and-get-started) or the [Quickstart](QUICKSTART.md) if not.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Setup
|
|
10
|
+
|
|
11
|
+
### Add the MCP server from `.mcp.json`
|
|
12
|
+
|
|
13
|
+
As an alternative to `claude mcp add` (see the README's [Connect to an MCP client](../README.md#connect-to-an-mcp-client)), place a `.mcp.json` file in your project directory — Claude Code auto-discovers it without any import command:
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"mcpServers": {
|
|
18
|
+
"eos": {
|
|
19
|
+
"command": "eos-mcp-server",
|
|
20
|
+
"args": [
|
|
21
|
+
"serve",
|
|
22
|
+
"--inventory",
|
|
23
|
+
"./ansible-inventory.yml"
|
|
24
|
+
],
|
|
25
|
+
"env": {
|
|
26
|
+
"EOS_MCP_PASSWORD": "replace-with-device-password"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Inventory
|
|
36
|
+
|
|
37
|
+
### List all devices and groups
|
|
38
|
+
|
|
39
|
+
> What devices are in the inventory?
|
|
40
|
+
|
|
41
|
+
> List the inventory
|
|
42
|
+
|
|
43
|
+
### Check connectivity to all devices
|
|
44
|
+
|
|
45
|
+
> Probe all the EOS devices in inventory
|
|
46
|
+
|
|
47
|
+
Example output: 8/8 devices reachable, showing hostname, endpoint IP, and EOS version.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Device Facts
|
|
52
|
+
|
|
53
|
+
### Collect facts across the entire fabric
|
|
54
|
+
|
|
55
|
+
> Get facts for all the EOS devices
|
|
56
|
+
|
|
57
|
+
Returns model, EOS version, serial number, uptime, and system MAC for every host.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Topology
|
|
62
|
+
|
|
63
|
+
### Generate a topology diagram from LLDP
|
|
64
|
+
|
|
65
|
+
> Create a topology diagram for all the devices using LLDP neighbors
|
|
66
|
+
|
|
67
|
+
Claude queries `show lldp neighbors` across all devices, infers the topology, and renders a Mermaid diagram. Example output for a 2-tier spine-leaf lab:
|
|
68
|
+
|
|
69
|
+
```mermaid
|
|
70
|
+
graph TB
|
|
71
|
+
subgraph tier1["Tier 1 — Spine"]
|
|
72
|
+
node1-1["node1-1\n172.20.20.2"]
|
|
73
|
+
node1-2["node1-2\n172.20.20.6"]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
subgraph tier2["Tier 2 — Leaf"]
|
|
77
|
+
node2-1["node2-1\n172.20.20.4"]
|
|
78
|
+
node2-2["node2-2\n172.20.20.5"]
|
|
79
|
+
node2-3["node2-3\n172.20.20.9"]
|
|
80
|
+
node2-4["node2-4\n172.20.20.7"]
|
|
81
|
+
node2-5["node2-5\n172.20.20.3"]
|
|
82
|
+
node2-6["node2-6\n172.20.20.8"]
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
node1-1 -- "Et1 ↔ Et1" --- node2-1
|
|
86
|
+
node1-1 -- "Et2 ↔ Et1" --- node2-2
|
|
87
|
+
node1-1 -- "Et3 ↔ Et1" --- node2-3
|
|
88
|
+
node1-1 -- "Et4 ↔ Et1" --- node2-4
|
|
89
|
+
node1-1 -- "Et5 ↔ Et1" --- node2-5
|
|
90
|
+
node1-1 -- "Et6 ↔ Et1" --- node2-6
|
|
91
|
+
|
|
92
|
+
node1-2 -- "Et1 ↔ Et2" --- node2-1
|
|
93
|
+
node1-2 -- "Et2 ↔ Et2" --- node2-2
|
|
94
|
+
node1-2 -- "Et3 ↔ Et2" --- node2-3
|
|
95
|
+
node1-2 -- "Et4 ↔ Et2" --- node2-4
|
|
96
|
+
node1-2 -- "Et5 ↔ Et2" --- node2-5
|
|
97
|
+
node1-2 -- "Et6 ↔ Et2" --- node2-6
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## VXLAN
|
|
103
|
+
|
|
104
|
+
### Check VXLAN status across all leaf switches
|
|
105
|
+
|
|
106
|
+
> Check on the VXLAN status for all the leaf switches
|
|
107
|
+
|
|
108
|
+
Claude runs `show vxlan vtep`, `show vxlan vni`, and `show interfaces Vxlan1` and summarizes:
|
|
109
|
+
|
|
110
|
+
- VTEP source IP and interface per leaf
|
|
111
|
+
- VNI-to-VLAN mappings
|
|
112
|
+
- Replication mode (headend VCS vs multicast)
|
|
113
|
+
- Flood list membership
|
|
114
|
+
- Interface line protocol status
|
|
115
|
+
|
|
116
|
+
### Example findings
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
node2-1 VTEP 192.168.2.3 Loopback1 VNI 1100 → VLAN 100 up
|
|
120
|
+
node2-2 VTEP 192.168.2.4 Loopback1 VNI 1100 → VLAN 100 up
|
|
121
|
+
node2-3 VTEP 192.168.2.5 Loopback1 VNI 1100 → VLAN 100 up
|
|
122
|
+
node2-4 VTEP 192.168.2.6 Loopback1 VNI 1100 → VLAN 100 up
|
|
123
|
+
node2-5 VTEP 192.168.2.7 Loopback1 VNI 1100 → VLAN 100 up
|
|
124
|
+
node2-6 VTEP 192.168.2.8 Loopback1 VNI 1100 → VLAN 100 up
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## BGP EVPN
|
|
130
|
+
|
|
131
|
+
### Check EVPN session and route state
|
|
132
|
+
|
|
133
|
+
> Check on EVPN
|
|
134
|
+
|
|
135
|
+
Claude runs `show bgp evpn summary` and `show bgp evpn` across all leaves and summarizes:
|
|
136
|
+
|
|
137
|
+
- Session state per peer (Established / Idle / etc.)
|
|
138
|
+
- Prefixes received and advertised per peer
|
|
139
|
+
- EVPN route types present (Type-2 MAC/IP, Type-3 IMET, etc.)
|
|
140
|
+
- ECMP path count per remote VTEP
|
|
141
|
+
- AS path to identify route reflectors and leaf ASNs
|
|
142
|
+
|
|
143
|
+
### Example findings
|
|
144
|
+
|
|
145
|
+
All 6 leaves peered to both spines (AS 65000), each leaf with a unique ASN (65001–65006). Only Type-3 IMET routes present — flood list built from EVPN, dual-path ECMP via both spines confirmed.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## VLANs
|
|
150
|
+
|
|
151
|
+
### Inspect a specific VLAN across all leaves
|
|
152
|
+
|
|
153
|
+
> What can you tell me about VLAN 100?
|
|
154
|
+
|
|
155
|
+
Claude runs `show vlan 100`, `show mac address-table vlan 100`, and `show interfaces Vlan100` across all leaves and reports:
|
|
156
|
+
|
|
157
|
+
- VLAN name and status on each leaf
|
|
158
|
+
- Which ports are members (access ports, trunk ports, VXLAN tunnel)
|
|
159
|
+
- MAC address table entries (learned hosts)
|
|
160
|
+
- Whether an SVI exists and its IP/state
|
|
161
|
+
|
|
162
|
+
### Example findings
|
|
163
|
+
|
|
164
|
+
VLAN 100 (`VLAN100`) active on all leaves, member of `Vx1` only, empty MAC table, no SVI — fully provisioned L2 overlay segment with no hosts connected yet.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Available Tools
|
|
169
|
+
|
|
170
|
+
| Tool | Description |
|
|
171
|
+
|---|---|
|
|
172
|
+
| `eos_probe_devices` | Validate connectivity, auth, and eAPI reachability |
|
|
173
|
+
| `eos_list_inventory` | Show eligible hosts and groups from the loaded inventory |
|
|
174
|
+
| `eos_get_facts` | Collect model, version, serial, uptime, system MAC |
|
|
175
|
+
| `eos_get_running_config` | Retrieve running config (full for hosts, section for groups) |
|
|
176
|
+
| `eos_run_show` | Run arbitrary `show ...` commands; returns JSON or text |
|
|
177
|
+
| `eos_show_logging` | Retrieve bounded logging output with minimum severity threshold |
|
|
178
|
+
| `eos_get_server_info` | Show server capabilities, runtime mode, inventory summary |
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# EOS MCP Server Implementation Plan
|
|
2
|
+
|
|
3
|
+
## Product boundary
|
|
4
|
+
|
|
5
|
+
The server is a permanent read-only MCP service. Scope is limited to inventory inspection, device probing, validated EOS `show` commands, bounded logging, facts, and running-configuration retrieval.
|
|
6
|
+
|
|
7
|
+
## Implemented work
|
|
8
|
+
|
|
9
|
+
- TypeScript ESM CLI and stdio MCP server.
|
|
10
|
+
- Canonical Ansible-style and simplified YAML inventories.
|
|
11
|
+
- Strict inventory validation, inherited variables, EOS eligibility, and fail-closed read policy.
|
|
12
|
+
- Inventory-authoritative host/group target resolution.
|
|
13
|
+
- HTTPS eAPI client with TLS validation, custom CA support, credential validation, request cancellation, and response-size limits.
|
|
14
|
+
- Seven MCP tools: server info, inventory, probe, show, logging, facts, and running configuration.
|
|
15
|
+
- Local `validate-inventory`, `print-server-info`, and `probe` commands.
|
|
16
|
+
- Bounded concurrency, target counts, command counts, logging messages, device responses, and aggregate tool responses.
|
|
17
|
+
- Unit, MCP stdio smoke, package-policy, and optional cEOS integration coverage.
|
|
18
|
+
|
|
19
|
+
## Ongoing priorities
|
|
20
|
+
|
|
21
|
+
1. Preserve the read-only tool boundary in schemas, CLI, inventory model, and MCP registration.
|
|
22
|
+
2. Maintain strict input validation and stable `AppError` codes.
|
|
23
|
+
3. Expand read-side test coverage when adding supported EOS query behavior.
|
|
24
|
+
4. Keep operator documentation synchronized with the tool and configuration surface.
|
|
25
|
+
5. Validate supported read behavior against maintained EOS/cEOS versions.
|
|
26
|
+
|
|
27
|
+
## Completion criteria
|
|
28
|
+
|
|
29
|
+
- Every registered MCP tool is read-only and inventory-scoped.
|
|
30
|
+
- All device-facing paths use the shared target, connection, timeout, and result-envelope safeguards.
|
|
31
|
+
- Documentation lists only supported tools and configuration fields.
|
|
32
|
+
- `npm test`, `npm run typecheck`, and `npm run build` pass.
|