@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.
Files changed (170) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/LICENSE +203 -0
  3. package/README.md +652 -0
  4. package/dist/cli.d.ts +16 -0
  5. package/dist/cli.js +188 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/commands/printServerInfo.d.ts +2 -0
  8. package/dist/commands/printServerInfo.js +14 -0
  9. package/dist/commands/printServerInfo.js.map +1 -0
  10. package/dist/commands/probe.d.ts +2 -0
  11. package/dist/commands/probe.js +26 -0
  12. package/dist/commands/probe.js.map +1 -0
  13. package/dist/commands/validateInventory.d.ts +9 -0
  14. package/dist/commands/validateInventory.js +59 -0
  15. package/dist/commands/validateInventory.js.map +1 -0
  16. package/dist/config/loadConfig.d.ts +3 -0
  17. package/dist/config/loadConfig.js +84 -0
  18. package/dist/config/loadConfig.js.map +1 -0
  19. package/dist/config/schema.d.ts +151 -0
  20. package/dist/config/schema.js +54 -0
  21. package/dist/config/schema.js.map +1 -0
  22. package/dist/configuration/getRunningConfig.d.ts +24 -0
  23. package/dist/configuration/getRunningConfig.js +38 -0
  24. package/dist/configuration/getRunningConfig.js.map +1 -0
  25. package/dist/connection/eosDeviceReader.d.ts +18 -0
  26. package/dist/connection/eosDeviceReader.js +13 -0
  27. package/dist/connection/eosDeviceReader.js.map +1 -0
  28. package/dist/connection/resolveConnection.d.ts +4 -0
  29. package/dist/connection/resolveConnection.js +58 -0
  30. package/dist/connection/resolveConnection.js.map +1 -0
  31. package/dist/connection/validateStartupConnections.d.ts +4 -0
  32. package/dist/connection/validateStartupConnections.js +28 -0
  33. package/dist/connection/validateStartupConnections.js.map +1 -0
  34. package/dist/core/errors.d.ts +8 -0
  35. package/dist/core/errors.js +22 -0
  36. package/dist/core/errors.js.map +1 -0
  37. package/dist/core/version.d.ts +2 -0
  38. package/dist/core/version.js +7 -0
  39. package/dist/core/version.js.map +1 -0
  40. package/dist/eapi/client.d.ts +8 -0
  41. package/dist/eapi/client.js +159 -0
  42. package/dist/eapi/client.js.map +1 -0
  43. package/dist/eapi/commands.d.ts +2 -0
  44. package/dist/eapi/commands.js +25 -0
  45. package/dist/eapi/commands.js.map +1 -0
  46. package/dist/eapi/transport.d.ts +21 -0
  47. package/dist/eapi/transport.js +143 -0
  48. package/dist/eapi/transport.js.map +1 -0
  49. package/dist/eapi/types.d.ts +49 -0
  50. package/dist/eapi/types.js +15 -0
  51. package/dist/eapi/types.js.map +1 -0
  52. package/dist/facts/getFacts.d.ts +33 -0
  53. package/dist/facts/getFacts.js +50 -0
  54. package/dist/facts/getFacts.js.map +1 -0
  55. package/dist/index.d.ts +2 -0
  56. package/dist/index.js +66 -0
  57. package/dist/index.js.map +1 -0
  58. package/dist/inventory/buildModel.d.ts +3 -0
  59. package/dist/inventory/buildModel.js +79 -0
  60. package/dist/inventory/buildModel.js.map +1 -0
  61. package/dist/inventory/effectiveVars.d.ts +2 -0
  62. package/dist/inventory/effectiveVars.js +52 -0
  63. package/dist/inventory/effectiveVars.js.map +1 -0
  64. package/dist/inventory/graph.d.ts +6 -0
  65. package/dist/inventory/graph.js +81 -0
  66. package/dist/inventory/graph.js.map +1 -0
  67. package/dist/inventory/internalTypes.d.ts +17 -0
  68. package/dist/inventory/internalTypes.js +2 -0
  69. package/dist/inventory/internalTypes.js.map +1 -0
  70. package/dist/inventory/internalUtils.d.ts +10 -0
  71. package/dist/inventory/internalUtils.js +68 -0
  72. package/dist/inventory/internalUtils.js.map +1 -0
  73. package/dist/inventory/listInventoryView.d.ts +23 -0
  74. package/dist/inventory/listInventoryView.js +22 -0
  75. package/dist/inventory/listInventoryView.js.map +1 -0
  76. package/dist/inventory/loadInventory.d.ts +4 -0
  77. package/dist/inventory/loadInventory.js +87 -0
  78. package/dist/inventory/loadInventory.js.map +1 -0
  79. package/dist/inventory/normalize.d.ts +4 -0
  80. package/dist/inventory/normalize.js +251 -0
  81. package/dist/inventory/normalize.js.map +1 -0
  82. package/dist/inventory/parse.d.ts +6 -0
  83. package/dist/inventory/parse.js +31 -0
  84. package/dist/inventory/parse.js.map +1 -0
  85. package/dist/inventory/policy.d.ts +11 -0
  86. package/dist/inventory/policy.js +27 -0
  87. package/dist/inventory/policy.js.map +1 -0
  88. package/dist/inventory/resolveTarget.d.ts +14 -0
  89. package/dist/inventory/resolveTarget.js +55 -0
  90. package/dist/inventory/resolveTarget.js.map +1 -0
  91. package/dist/inventory/types.d.ts +50 -0
  92. package/dist/inventory/types.js +2 -0
  93. package/dist/inventory/types.js.map +1 -0
  94. package/dist/inventory/validateNormalized.d.ts +2 -0
  95. package/dist/inventory/validateNormalized.js +64 -0
  96. package/dist/inventory/validateNormalized.js.map +1 -0
  97. package/dist/inventory/varValidation.d.ts +2 -0
  98. package/dist/inventory/varValidation.js +60 -0
  99. package/dist/inventory/varValidation.js.map +1 -0
  100. package/dist/inventory/writePolicy.d.ts +2 -0
  101. package/dist/inventory/writePolicy.js +36 -0
  102. package/dist/inventory/writePolicy.js.map +1 -0
  103. package/dist/logging/loggingQuery.d.ts +15 -0
  104. package/dist/logging/loggingQuery.js +38 -0
  105. package/dist/logging/loggingQuery.js.map +1 -0
  106. package/dist/logging/showLogging.d.ts +28 -0
  107. package/dist/logging/showLogging.js +37 -0
  108. package/dist/logging/showLogging.js.map +1 -0
  109. package/dist/mcp/createServer.d.ts +3 -0
  110. package/dist/mcp/createServer.js +82 -0
  111. package/dist/mcp/createServer.js.map +1 -0
  112. package/dist/mcp/toolResult.d.ts +7 -0
  113. package/dist/mcp/toolResult.js +13 -0
  114. package/dist/mcp/toolResult.js.map +1 -0
  115. package/dist/mcp/tools/getFacts.d.ts +21 -0
  116. package/dist/mcp/tools/getFacts.js +17 -0
  117. package/dist/mcp/tools/getFacts.js.map +1 -0
  118. package/dist/mcp/tools/getRunningConfig.d.ts +21 -0
  119. package/dist/mcp/tools/getRunningConfig.js +17 -0
  120. package/dist/mcp/tools/getRunningConfig.js.map +1 -0
  121. package/dist/mcp/tools/getServerInfo.d.ts +10 -0
  122. package/dist/mcp/tools/getServerInfo.js +9 -0
  123. package/dist/mcp/tools/getServerInfo.js.map +1 -0
  124. package/dist/mcp/tools/listInventory.d.ts +16 -0
  125. package/dist/mcp/tools/listInventory.js +15 -0
  126. package/dist/mcp/tools/listInventory.js.map +1 -0
  127. package/dist/mcp/tools/probeDevices.d.ts +21 -0
  128. package/dist/mcp/tools/probeDevices.js +14 -0
  129. package/dist/mcp/tools/probeDevices.js.map +1 -0
  130. package/dist/mcp/tools/runShow.d.ts +30 -0
  131. package/dist/mcp/tools/runShow.js +34 -0
  132. package/dist/mcp/tools/runShow.js.map +1 -0
  133. package/dist/mcp/tools/showLogging.d.ts +24 -0
  134. package/dist/mcp/tools/showLogging.js +20 -0
  135. package/dist/mcp/tools/showLogging.js.map +1 -0
  136. package/dist/operations/readExecution.d.ts +57 -0
  137. package/dist/operations/readExecution.js +132 -0
  138. package/dist/operations/readExecution.js.map +1 -0
  139. package/dist/probe/probeDevices.d.ts +24 -0
  140. package/dist/probe/probeDevices.js +24 -0
  141. package/dist/probe/probeDevices.js.map +1 -0
  142. package/dist/serverInfo/buildServerInfo.d.ts +2 -0
  143. package/dist/serverInfo/buildServerInfo.js +49 -0
  144. package/dist/serverInfo/buildServerInfo.js.map +1 -0
  145. package/dist/serverInfo/types.d.ts +46 -0
  146. package/dist/serverInfo/types.js +2 -0
  147. package/dist/serverInfo/types.js.map +1 -0
  148. package/dist/show/runShow.d.ts +29 -0
  149. package/dist/show/runShow.js +40 -0
  150. package/dist/show/runShow.js.map +1 -0
  151. package/dist/utils/json.d.ts +1 -0
  152. package/dist/utils/json.js +4 -0
  153. package/dist/utils/json.js.map +1 -0
  154. package/dist/utils/path.d.ts +2 -0
  155. package/dist/utils/path.js +14 -0
  156. package/dist/utils/path.js.map +1 -0
  157. package/dist/utils/value.d.ts +6 -0
  158. package/dist/utils/value.js +28 -0
  159. package/dist/utils/value.js.map +1 -0
  160. package/docs/CHECKPOINT.md +46 -0
  161. package/docs/CODE_WALKTHROUGH.md +112 -0
  162. package/docs/DESIGN.md +56 -0
  163. package/docs/DEVELOPMENT.md +72 -0
  164. package/docs/EXAMPLES.md +178 -0
  165. package/docs/IMPLEMENTATION_PLAN.md +32 -0
  166. package/docs/QUICKSTART.md +152 -0
  167. package/example-inventories/canonical-fabric.yaml +45 -0
  168. package/example-inventories/multi-password.yaml +35 -0
  169. package/example-inventories/simplified-lab.yaml +33 -0
  170. package/package.json +57 -0
@@ -0,0 +1,24 @@
1
+ import type { ResolvedServerConfig } from "../config/schema.js";
2
+ import type { EosDeviceReader } from "../connection/eosDeviceReader.js";
3
+ import type { InventoryModel } from "../inventory/types.js";
4
+ import { type DeviceResultSummary } from "../operations/readExecution.js";
5
+ export interface GetRunningConfigOptions {
6
+ target: string;
7
+ section?: string;
8
+ }
9
+ export interface GetRunningConfigResult {
10
+ target: string;
11
+ target_type: "host" | "group";
12
+ section_requested: string | null;
13
+ resolved_devices: string[];
14
+ summary: DeviceResultSummary;
15
+ results: Array<{
16
+ inventory_hostname: string;
17
+ resolved_endpoint: string;
18
+ status: "success" | "failed";
19
+ config_text?: string;
20
+ error_code?: string;
21
+ message?: string;
22
+ }>;
23
+ }
24
+ export declare function getRunningConfig(model: InventoryModel, config: ResolvedServerConfig, options: GetRunningConfigOptions, reader: EosDeviceReader): Promise<GetRunningConfigResult>;
@@ -0,0 +1,38 @@
1
+ import { AppError } from "../core/errors.js";
2
+ import { normalizeSingleLineEosInput } from "../eapi/commands.js";
3
+ import { buildReadDeviceFailure, buildReadDeviceSuccess, buildReadOperationResultEnvelope, executeReadOperation } from "../operations/readExecution.js";
4
+ export async function getRunningConfig(model, config, options, reader) {
5
+ const section = options.section !== undefined ? normalizeSingleLineEosInput(options.section, "running config section") : undefined;
6
+ const command = section ? `show running-config section ${section}` : "show running-config";
7
+ const operation = await executeReadOperation(model, config, {
8
+ target: options.target,
9
+ operationName: "eos_get_running_config",
10
+ validateTarget: (resolvedTarget) => {
11
+ if (resolvedTarget.targetType === "group" && !section) {
12
+ throw new AppError("running_config_section_required", "Group targets for eos_get_running_config require a section");
13
+ }
14
+ },
15
+ run: async (host, signal) => buildReadDeviceSuccess(host, {
16
+ config_text: extractConfigText(await reader.runShowCommands(host, [command], "text", { enable: true, signal }))
17
+ }),
18
+ onError: (host, error) => buildReadDeviceFailure(host, "running_config_failed", error)
19
+ });
20
+ return buildReadOperationResultEnvelope(options.target, operation, {
21
+ extra: {
22
+ section_requested: section ?? null
23
+ },
24
+ responseSizeLimit: {
25
+ config,
26
+ operationName: "eos_get_running_config",
27
+ narrowingGuidance: "Use a section filter to retrieve only the relevant portion of the running config (e.g., section \"router bgp\")."
28
+ }
29
+ });
30
+ }
31
+ function extractConfigText(commandResults) {
32
+ const first = commandResults[0]?.output;
33
+ if (typeof first === "string") {
34
+ return first;
35
+ }
36
+ throw new AppError("running_config_payload_invalid", "Unexpected running-config payload structure");
37
+ }
38
+ //# sourceMappingURL=getRunningConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getRunningConfig.js","sourceRoot":"","sources":["../../src/configuration/getRunningConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE7C,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAIlE,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,gCAAgC,EAChC,oBAAoB,EAErB,MAAM,gCAAgC,CAAC;AAuBxC,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,KAAqB,EACrB,MAA4B,EAC5B,OAAgC,EAChC,MAAuB;IAEvB,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,2BAA2B,CAAC,OAAO,CAAC,OAAO,EAAE,wBAAwB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACnI,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,+BAA+B,OAAO,EAAE,CAAC,CAAC,CAAC,qBAAqB,CAAC;IAC3F,MAAM,SAAS,GAAG,MAAM,oBAAoB,CAA4C,KAAK,EAAE,MAAM,EAAE;QACrG,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,aAAa,EAAE,wBAAwB;QACvC,cAAc,EAAE,CAAC,cAAc,EAAE,EAAE;YACjC,IAAI,cAAc,CAAC,UAAU,KAAK,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC;gBACtD,MAAM,IAAI,QAAQ,CAAC,iCAAiC,EAAE,4DAA4D,CAAC,CAAC;YACtH,CAAC;QACH,CAAC;QACD,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAC1B,sBAAsB,CAAC,IAAI,EAAE;YAC3B,WAAW,EAAE,iBAAiB,CAAC,MAAM,MAAM,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;SAChH,CAAC;QACJ,OAAO,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,sBAAsB,CAAC,IAAI,EAAE,uBAAuB,EAAE,KAAK,CAAC;KACvF,CAAC,CAAC;IAEH,OAAO,gCAAgC,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE;QACjE,KAAK,EAAE;YACL,iBAAiB,EAAE,OAAO,IAAI,IAAI;SACnC;QACD,iBAAiB,EAAE;YACjB,MAAM;YACN,aAAa,EAAE,wBAAwB;YACvC,iBAAiB,EAAE,kHAAkH;SACtI;KACF,CAAC,CAAC;AACL,CAAC;AAED,SAAS,iBAAiB,CAAC,cAAkC;IAC3D,MAAM,KAAK,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC;IAExC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,IAAI,QAAQ,CAAC,gCAAgC,EAAE,6CAA6C,CAAC,CAAC;AACtG,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { ResolvedServerConfig } from "../config/schema.js";
2
+ import type { EosCommandResult, EosCommandRunner, EapiOutputMode, RunShowCommandOptions } from "../eapi/types.js";
3
+ import type { InventoryHostModel } from "../inventory/types.js";
4
+ /**
5
+ * Runs EOS read commands for an inventory host.
6
+ *
7
+ * Callers provide inventory identity and command intent; this module owns
8
+ * resolving credentials, endpoint, and TLS settings for the eAPI adapter.
9
+ */
10
+ export interface EosDeviceReader {
11
+ runShowCommands(host: InventoryHostModel, commands: string[], outputMode: EapiOutputMode, options?: RunShowCommandOptions): Promise<EosCommandResult[]>;
12
+ }
13
+ export declare class EapiDeviceReader implements EosDeviceReader {
14
+ private readonly config;
15
+ private readonly runner;
16
+ constructor(config: ResolvedServerConfig, runner: EosCommandRunner);
17
+ runShowCommands(host: InventoryHostModel, commands: string[], outputMode: EapiOutputMode, options?: RunShowCommandOptions): Promise<EosCommandResult[]>;
18
+ }
@@ -0,0 +1,13 @@
1
+ import { resolveEapiConnection } from "./resolveConnection.js";
2
+ export class EapiDeviceReader {
3
+ config;
4
+ runner;
5
+ constructor(config, runner) {
6
+ this.config = config;
7
+ this.runner = runner;
8
+ }
9
+ runShowCommands(host, commands, outputMode, options) {
10
+ return this.runner.runShowCommands(resolveEapiConnection(this.config, host), commands, outputMode, options);
11
+ }
12
+ }
13
+ //# sourceMappingURL=eosDeviceReader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eosDeviceReader.js","sourceRoot":"","sources":["../../src/connection/eosDeviceReader.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAiB/D,MAAM,OAAO,gBAAgB;IAER;IACA;IAFnB,YACmB,MAA4B,EAC5B,MAAwB;QADxB,WAAM,GAAN,MAAM,CAAsB;QAC5B,WAAM,GAAN,MAAM,CAAkB;IACxC,CAAC;IAEJ,eAAe,CACb,IAAwB,EACxB,QAAkB,EAClB,UAA0B,EAC1B,OAA+B;QAE/B,OAAO,IAAI,CAAC,MAAM,CAAC,eAAe,CAChC,qBAAqB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,EACxC,QAAQ,EACR,UAAU,EACV,OAAO,CACR,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,4 @@
1
+ import type { ResolvedServerConfig } from "../config/schema.js";
2
+ import type { InventoryHostModel } from "../inventory/types.js";
3
+ import type { EapiConnectionConfig } from "../eapi/types.js";
4
+ export declare function resolveEapiConnection(config: ResolvedServerConfig, host: InventoryHostModel): EapiConnectionConfig;
@@ -0,0 +1,58 @@
1
+ import { AppError } from "../core/errors.js";
2
+ import { readBoolean, readNonEmptyString, readPositiveInteger } from "../utils/value.js";
3
+ export function resolveEapiConnection(config, host) {
4
+ const effectiveVars = host.effectiveVars;
5
+ const endpointHost = host.resolvedEndpoint;
6
+ const port = readPositiveInteger(effectiveVars.ansible_httpapi_port) ?? config.defaultConnection.ansibleHttpapiPort ?? 443;
7
+ const username = readNonEmptyString(effectiveVars.ansible_user) ?? config.defaultConnection.ansibleUser;
8
+ if (!username) {
9
+ throw new AppError("connection_username_missing", `Missing effective username for host ${host.inventoryHostname}`);
10
+ }
11
+ const hostPasswordSources = [];
12
+ const passwordEnv = readNonEmptyString(effectiveVars.mcp_password_env);
13
+ const literalPassword = readNonEmptyString(effectiveVars.ansible_password);
14
+ const defaultPasswordEnv = config.defaultConnection.mcpPasswordEnv;
15
+ if (passwordEnv) {
16
+ hostPasswordSources.push({ kind: "env", value: passwordEnv });
17
+ }
18
+ if (literalPassword) {
19
+ hostPasswordSources.push({ kind: "literal", value: literalPassword });
20
+ }
21
+ if (hostPasswordSources.length > 1) {
22
+ throw new AppError("connection_password_source_invalid", `Expected exactly one effective password source for host ${host.inventoryHostname}`);
23
+ }
24
+ const passwordSource = hostPasswordSources[0] ?? (defaultPasswordEnv ? { kind: "env", value: defaultPasswordEnv } : undefined);
25
+ if (!passwordSource) {
26
+ throw new AppError("connection_password_source_missing", `Missing password source for host ${host.inventoryHostname}`);
27
+ }
28
+ const password = passwordSource.kind === "literal"
29
+ ? passwordSource.value
30
+ : resolvePasswordFromEnv(config.secretEnvPrefixes, passwordSource.value, host.inventoryHostname);
31
+ const validateCerts = readBoolean(effectiveVars.mcp_validate_certs) ??
32
+ readBoolean(effectiveVars.ansible_httpapi_validate_certs) ??
33
+ config.defaultConnection.mcpValidateCerts ??
34
+ true;
35
+ return {
36
+ inventoryHostname: host.inventoryHostname,
37
+ endpointHost,
38
+ baseUrl: `https://${endpointHost}:${port}/command-api`,
39
+ username,
40
+ password,
41
+ validateCerts,
42
+ ...(config.caFile !== undefined ? { caFile: config.caFile } : {}),
43
+ timeoutMs: config.readTimeoutMs,
44
+ eapiVersion: config.eapiVersion,
45
+ maxResponseSizeBytes: config.maxResponseSizeBytes
46
+ };
47
+ }
48
+ function resolvePasswordFromEnv(prefixes, envName, hostName) {
49
+ if (!prefixes.some((prefix) => envName.startsWith(prefix))) {
50
+ throw new AppError("connection_password_env_prefix_invalid", `Password env var ${envName} for host ${hostName} does not match any allowed prefix`);
51
+ }
52
+ const value = process.env[envName];
53
+ if (!value) {
54
+ throw new AppError("connection_password_env_missing", `Password env var ${envName} for host ${hostName} is not set`);
55
+ }
56
+ return value;
57
+ }
58
+ //# sourceMappingURL=resolveConnection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveConnection.js","sourceRoot":"","sources":["../../src/connection/resolveConnection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { ResolvedServerConfig } from "../config/schema.js";
2
+ import type { InventoryModel, InventoryValidationError } from "../inventory/types.js";
3
+ export declare function collectStartupConnectionValidationErrors(config: ResolvedServerConfig, model: InventoryModel): InventoryValidationError[];
4
+ export declare function validateStartupConnections(config: ResolvedServerConfig, model: InventoryModel): void;
@@ -0,0 +1,28 @@
1
+ import { AppError, getErrorCode, toErrorMessage } from "../core/errors.js";
2
+ import { resolveEapiConnection } from "./resolveConnection.js";
3
+ export function collectStartupConnectionValidationErrors(config, model) {
4
+ const errors = [];
5
+ for (const host of model.hosts) {
6
+ if (!host.eligible) {
7
+ continue;
8
+ }
9
+ try {
10
+ resolveEapiConnection(config, host);
11
+ }
12
+ catch (error) {
13
+ errors.push({
14
+ code: getErrorCode(error) ?? "startup_connection_invalid",
15
+ message: `${host.inventoryHostname}: ${toErrorMessage(error)}`,
16
+ path: host.inventoryHostname
17
+ });
18
+ }
19
+ }
20
+ return errors;
21
+ }
22
+ export function validateStartupConnections(config, model) {
23
+ const errors = collectStartupConnectionValidationErrors(config, model);
24
+ if (errors.length > 0) {
25
+ throw new AppError("startup_connection_validation_failed", `Startup connection validation failed: ${errors.map((error) => error.message).join("; ")}`, { errors });
26
+ }
27
+ }
28
+ //# sourceMappingURL=validateStartupConnections.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validateStartupConnections.js","sourceRoot":"","sources":["../../src/connection/validateStartupConnections.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAG3E,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,MAAM,UAAU,wCAAwC,CACtD,MAA4B,EAC5B,KAAqB;IAErB,MAAM,MAAM,GAA+B,EAAE,CAAC;IAE9C,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAC/B,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,SAAS;QACX,CAAC;QAED,IAAI,CAAC;YACH,qBAAqB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,YAAY,CAAC,KAAK,CAAC,IAAI,4BAA4B;gBACzD,OAAO,EAAE,GAAG,IAAI,CAAC,iBAAiB,KAAK,cAAc,CAAC,KAAK,CAAC,EAAE;gBAC9D,IAAI,EAAE,IAAI,CAAC,iBAAiB;aAC7B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,MAA4B,EAAE,KAAqB;IAC5F,MAAM,MAAM,GAAG,wCAAwC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAEvE,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,QAAQ,CAChB,sCAAsC,EACtC,yCAAyC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAC1F,EAAE,MAAM,EAAE,CACX,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,8 @@
1
+ export declare class AppError extends Error {
2
+ readonly code: string;
3
+ readonly details?: Record<string, unknown>;
4
+ constructor(code: string, message: string, details?: Record<string, unknown>);
5
+ }
6
+ export declare function getErrorCode(error: unknown): string | undefined;
7
+ export declare function toErrorCode(error: unknown, fallback?: string): string;
8
+ export declare function toErrorMessage(error: unknown): string;
@@ -0,0 +1,22 @@
1
+ export class AppError extends Error {
2
+ code;
3
+ details;
4
+ constructor(code, message, details) {
5
+ super(message);
6
+ this.name = new.target.name;
7
+ this.code = code;
8
+ if (details !== undefined) {
9
+ this.details = details;
10
+ }
11
+ }
12
+ }
13
+ export function getErrorCode(error) {
14
+ return error instanceof AppError ? error.code : undefined;
15
+ }
16
+ export function toErrorCode(error, fallback = "unknown_error") {
17
+ return getErrorCode(error) ?? fallback;
18
+ }
19
+ export function toErrorMessage(error) {
20
+ return error instanceof Error ? error.message : String(error);
21
+ }
22
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,QAAS,SAAQ,KAAK;IACxB,IAAI,CAAS;IACb,OAAO,CAA2B;IAE3C,YAAY,IAAY,EAAE,OAAe,EAAE,OAAiC;QAC1E,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACzB,CAAC;IACH,CAAC;CACF;AAED,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,OAAO,KAAK,YAAY,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAc,EAAE,QAAQ,GAAG,eAAe;IACpE,OAAO,YAAY,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const APP_NAME: string;
2
+ export declare const APP_VERSION: string;
@@ -0,0 +1,7 @@
1
+ import { createRequire } from "node:module";
2
+ const require = createRequire(import.meta.url);
3
+ const packageJson = require("../../package.json");
4
+ // The npm package name is scoped (@aristanetworks/...); the CLI and MCP server identify as the bin command name.
5
+ export const APP_NAME = Object.keys(packageJson.bin)[0] ?? "eos-mcp-server";
6
+ export const APP_VERSION = packageJson.version;
7
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/core/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,WAAW,GAAG,OAAO,CAAC,oBAAoB,CAAqD,CAAC;AAEtG,iHAAiH;AACjH,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,gBAAgB,CAAC;AAC5E,MAAM,CAAC,MAAM,WAAW,GAAG,WAAW,CAAC,OAAO,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { type EapiConnectionConfig, type EapiOutputMode, type EosCommandResult, type RunShowCommandOptions } from "./types.js";
2
+ import { type EapiTransport } from "./transport.js";
3
+ export declare class EapiClient {
4
+ private readonly transport;
5
+ constructor(transport?: EapiTransport);
6
+ runShowCommands(connection: EapiConnectionConfig, commands: string[], outputMode: EapiOutputMode, options?: RunShowCommandOptions): Promise<EosCommandResult[]>;
7
+ private runCommands;
8
+ }
@@ -0,0 +1,159 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { AppError, getErrorCode } from "../core/errors.js";
3
+ import { isObject } from "../utils/value.js";
4
+ import { hasEapiResultArray, parseEapiRunCmdsResponse } from "./types.js";
5
+ import { NodeHttpsEapiTransport } from "./transport.js";
6
+ export class EapiClient {
7
+ transport;
8
+ constructor(transport = new NodeHttpsEapiTransport()) {
9
+ this.transport = transport;
10
+ }
11
+ async runShowCommands(connection, commands, outputMode, options) {
12
+ const run = async (format) => {
13
+ const payload = await this.runCommands(connection, commands, format, options);
14
+ return buildCommandResults(payload, commands, format, options?.includeRawEntries === true);
15
+ };
16
+ if (outputMode === "json" || outputMode === "text") {
17
+ return run(outputMode);
18
+ }
19
+ try {
20
+ return await run("json");
21
+ }
22
+ catch (error) {
23
+ if (getErrorCode(error) !== "json_output_unavailable") {
24
+ throw error;
25
+ }
26
+ return run("text");
27
+ }
28
+ }
29
+ async runCommands(connection, commands, format, options) {
30
+ if (commands.length === 0) {
31
+ throw new AppError("eapi_commands_missing", "runCommands requires at least one command");
32
+ }
33
+ const useEnable = options?.enable === true;
34
+ const wireCommands = useEnable ? ["enable", ...commands] : commands;
35
+ const requestBody = {
36
+ jsonrpc: "2.0",
37
+ method: "runCmds",
38
+ params: {
39
+ version: connection.eapiVersion,
40
+ cmds: wireCommands,
41
+ format
42
+ },
43
+ id: randomUUID()
44
+ };
45
+ const requestSignal = buildRequestSignal(connection.timeoutMs, options?.signal);
46
+ const requestJson = JSON.stringify(requestBody);
47
+ let response;
48
+ try {
49
+ response = await this.transport.postJson(connection, requestJson, requestSignal);
50
+ }
51
+ catch (error) {
52
+ throw classifyTransportError(error, requestSignal, connection);
53
+ }
54
+ if (!response.ok) {
55
+ const text = await response.text();
56
+ throw new AppError("eapi_http_error", `EOS eAPI request failed with status ${response.status}: ${text}`, {
57
+ status: response.status
58
+ });
59
+ }
60
+ const payload = await parseJsonResponse(response, connection);
61
+ throwIfJsonRpcError(payload);
62
+ const normalizedPayload = useEnable ? stripEnableResult(payload) : payload;
63
+ parseEapiRunCmdsResponse(normalizedPayload, commands.length);
64
+ return normalizedPayload;
65
+ }
66
+ }
67
+ function buildRequestSignal(timeoutMs, callerSignal) {
68
+ const timeoutSignal = AbortSignal.timeout(timeoutMs);
69
+ return callerSignal === undefined ? timeoutSignal : AbortSignal.any([callerSignal, timeoutSignal]);
70
+ }
71
+ function buildCommandResults(payload, commands, outputFormat, includeRawEntries) {
72
+ const entries = parseEapiRunCmdsResponse(payload, commands.length).result;
73
+ return commands.map((command, index) => {
74
+ const rawEntry = entries[index];
75
+ const output = outputFormat === "text" ? extractStrictTextOutput(rawEntry, command) : rawEntry;
76
+ return {
77
+ command,
78
+ output_format: outputFormat,
79
+ output,
80
+ ...(includeRawEntries ? { raw_entry: rawEntry } : {})
81
+ };
82
+ });
83
+ }
84
+ function extractStrictTextOutput(entry, command) {
85
+ if (typeof entry === "string") {
86
+ return entry;
87
+ }
88
+ if (isObject(entry) && typeof entry.output === "string") {
89
+ return entry.output;
90
+ }
91
+ throw new AppError("eapi_text_output_invalid", `Unexpected text output payload for command ${command}`);
92
+ }
93
+ async function parseJsonResponse(response, connection) {
94
+ try {
95
+ return await response.json();
96
+ }
97
+ catch (error) {
98
+ const message = error instanceof Error ? error.message : String(error);
99
+ throw new AppError("eapi_response_invalid_json", `EOS eAPI response for host ${connection.inventoryHostname} was not valid JSON: ${message}`, {
100
+ inventoryHostname: connection.inventoryHostname
101
+ });
102
+ }
103
+ }
104
+ function classifyTransportError(error, signal, connection) {
105
+ if (error instanceof AppError) {
106
+ return error;
107
+ }
108
+ if (signal.aborted) {
109
+ const reason = signal.reason;
110
+ if (reason instanceof AppError) {
111
+ return reason;
112
+ }
113
+ if (isTimeoutAbortReason(reason)) {
114
+ return new AppError("eapi_request_timeout", `EOS eAPI request for host ${connection.inventoryHostname} exceeded readTimeoutMs ${connection.timeoutMs}`, {
115
+ inventoryHostname: connection.inventoryHostname,
116
+ timeoutMs: connection.timeoutMs
117
+ });
118
+ }
119
+ return new AppError("eapi_request_aborted", `EOS eAPI request for host ${connection.inventoryHostname} was aborted`, {
120
+ inventoryHostname: connection.inventoryHostname
121
+ });
122
+ }
123
+ const message = error instanceof Error ? error.message : String(error);
124
+ return new AppError("eapi_transport_error", `EOS eAPI transport error for host ${connection.inventoryHostname}: ${message}`, {
125
+ inventoryHostname: connection.inventoryHostname
126
+ });
127
+ }
128
+ function isTimeoutAbortReason(reason) {
129
+ return reason instanceof DOMException && reason.name === "TimeoutError";
130
+ }
131
+ function stripEnableResult(payload) {
132
+ if (hasEapiResultArray(payload)) {
133
+ return { ...payload, result: payload.result.slice(1) };
134
+ }
135
+ return payload;
136
+ }
137
+ function throwIfJsonRpcError(payload) {
138
+ if (!isObject(payload) || !isObject(payload.error)) {
139
+ return;
140
+ }
141
+ const message = typeof payload.error.message === "string" ? payload.error.message : "EOS eAPI JSON-RPC error";
142
+ const code = typeof payload.error.code === "number" || typeof payload.error.code === "string" ? payload.error.code : "unknown";
143
+ const data = payload.error.data;
144
+ const details = data === undefined ? "" : `; data=${JSON.stringify(data)}`;
145
+ throw new AppError(classifyJsonRpcErrorCode(message, data), `EOS eAPI JSON-RPC error ${String(code)}: ${message}${details}`, {
146
+ jsonRpcCode: code,
147
+ ...(data !== undefined ? { data } : {})
148
+ });
149
+ }
150
+ function classifyJsonRpcErrorCode(message, data) {
151
+ const haystacks = [message, ...(Array.isArray(data) ? data.filter((entry) => typeof entry === "string") : [])]
152
+ .join(" ")
153
+ .toLowerCase();
154
+ if (haystacks.includes("json")) {
155
+ return "json_output_unavailable";
156
+ }
157
+ return "eapi_json_rpc_error";
158
+ }
159
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/eapi/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function normalizeSingleLineEosInput(value: string, label: string): string;
2
+ export declare function normalizeShowCommand(command: string): string;
@@ -0,0 +1,25 @@
1
+ import { AppError } from "../core/errors.js";
2
+ const CONTROL_CHARACTER_PATTERN = /[\u0000-\u001f\u007f]/;
3
+ const RISKY_CLI_META_PATTERN = /[|><;&`$]/;
4
+ export function normalizeSingleLineEosInput(value, label) {
5
+ const normalized = value.trim();
6
+ if (normalized.length === 0) {
7
+ throw new AppError("eos_input_empty", `${label} must not be empty`);
8
+ }
9
+ if (CONTROL_CHARACTER_PATTERN.test(normalized)) {
10
+ throw new AppError("eos_input_invalid", `${label} must be a single line without control characters`);
11
+ }
12
+ if (RISKY_CLI_META_PATTERN.test(normalized)) {
13
+ throw new AppError("eos_input_invalid", `${label} must not contain CLI output modifiers or shell metacharacters`);
14
+ }
15
+ return normalized;
16
+ }
17
+ export function normalizeShowCommand(command) {
18
+ const normalized = normalizeSingleLineEosInput(command, "show command");
19
+ const lower = normalized.toLowerCase();
20
+ if (lower !== "show" && !lower.startsWith("show ")) {
21
+ throw new AppError("show_command_invalid", `Only show commands are allowed in eos_run_show: ${command}`);
22
+ }
23
+ return normalized;
24
+ }
25
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/eapi/commands.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE7C,MAAM,yBAAyB,GAAG,uBAAuB,CAAC;AAC1D,MAAM,sBAAsB,GAAG,WAAW,CAAC;AAE3C,MAAM,UAAU,2BAA2B,CAAC,KAAa,EAAE,KAAa;IACtE,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAEhC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,QAAQ,CAAC,iBAAiB,EAAE,GAAG,KAAK,oBAAoB,CAAC,CAAC;IACtE,CAAC;IAED,IAAI,yBAAyB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,QAAQ,CAAC,mBAAmB,EAAE,GAAG,KAAK,mDAAmD,CAAC,CAAC;IACvG,CAAC;IAED,IAAI,sBAAsB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5C,MAAM,IAAI,QAAQ,CAAC,mBAAmB,EAAE,GAAG,KAAK,gEAAgE,CAAC,CAAC;IACpH,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,OAAe;IAClD,MAAM,UAAU,GAAG,2BAA2B,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;IACxE,MAAM,KAAK,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC;IAEvC,IAAI,KAAK,KAAK,MAAM,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACnD,MAAM,IAAI,QAAQ,CAAC,sBAAsB,EAAE,mDAAmD,OAAO,EAAE,CAAC,CAAC;IAC3G,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { EapiConnectionConfig } from "./types.js";
2
+ export interface EapiHttpResponse {
3
+ ok: boolean;
4
+ status: number;
5
+ json(): Promise<unknown>;
6
+ text(): Promise<string>;
7
+ }
8
+ export interface EapiTransport {
9
+ postJson(connection: EapiConnectionConfig, requestJson: string, signal: AbortSignal): Promise<EapiHttpResponse>;
10
+ }
11
+ export type FetchLike = (input: string, init?: RequestInit) => Promise<EapiHttpResponse>;
12
+ export declare class FetchEapiTransport implements EapiTransport {
13
+ private readonly fetchFn;
14
+ constructor(fetchFn: FetchLike);
15
+ postJson(connection: EapiConnectionConfig, requestJson: string, signal: AbortSignal): Promise<EapiHttpResponse>;
16
+ }
17
+ export declare class NodeHttpsEapiTransport implements EapiTransport {
18
+ private readonly caCache;
19
+ postJson(connection: EapiConnectionConfig, requestJson: string, signal: AbortSignal): Promise<EapiHttpResponse>;
20
+ private readCaFile;
21
+ }