@access-mcp/xdmod 0.6.0

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/README.md ADDED
@@ -0,0 +1,113 @@
1
+ # XDMoD MCP Server
2
+
3
+ MCP server for public XDMoD data: charts, visualizations, metadata discovery, and dimension values from the XDMoD (XD Metrics on Demand) Usage Analytics API.
4
+
5
+ ## Usage Examples
6
+
7
+ ### Charts & Visualizations
8
+ ```
9
+ "CPU hours chart for January 2024 (PNG)"
10
+ "Job count data for last 30 days"
11
+ "GPU usage SVG chart grouped by resource"
12
+ "Average wait time visualization for Q1 2024"
13
+ ```
14
+
15
+ ### Portal Links
16
+ ```
17
+ "XDMoD portal link for CPU hours chart"
18
+ "Interactive GPU usage view in portal"
19
+ "Job count chart link for Bridges-2"
20
+ ```
21
+
22
+ ## Tools
23
+
24
+ ### `get_chart_data`
25
+
26
+ Get chart data and metadata for a specific statistic.
27
+
28
+ **Parameters:**
29
+ | Parameter | Type | Description |
30
+ |-----------|------|-------------|
31
+ | `realm` | string | The realm (e.g., "Jobs") |
32
+ | `group_by` | string | The group by field (e.g., "none") |
33
+ | `statistic` | string | The statistic name (e.g., "total_cpu_hours") |
34
+ | `start_date` | string | Start date (YYYY-MM-DD) |
35
+ | `end_date` | string | End date (YYYY-MM-DD) |
36
+ | `dataset_type` | string | Dataset type (default: "timeseries") |
37
+
38
+ ### `get_chart_image`
39
+
40
+ Get chart image (SVG, PNG, or PDF) for a specific statistic.
41
+
42
+ **Parameters:**
43
+ | Parameter | Type | Description |
44
+ |-----------|------|-------------|
45
+ | `realm` | string | The realm (e.g., "Jobs") |
46
+ | `group_by` | string | The group by field (e.g., "none") |
47
+ | `statistic` | string | The statistic name (e.g., "total_cpu_hours") |
48
+ | `start_date` | string | Start date (YYYY-MM-DD) |
49
+ | `end_date` | string | End date (YYYY-MM-DD) |
50
+ | `format` | string | Image format: "svg", "png", or "pdf" (default: "svg") |
51
+ | `width` | number | Image width in pixels (default: 916) |
52
+ | `height` | number | Image height in pixels (default: 484) |
53
+ | `dataset_type` | string | Dataset type (default: "timeseries") |
54
+
55
+ ### `get_chart_link`
56
+
57
+ Generate a direct link to view the chart in the XDMoD portal.
58
+
59
+ **Parameters:**
60
+ | Parameter | Type | Description |
61
+ |-----------|------|-------------|
62
+ | `realm` | string | The realm (e.g., "Jobs", "SUPREMM") |
63
+ | `group_by` | string | The group by field (e.g., "none", "resource") |
64
+ | `statistic` | string | The statistic name (e.g., "total_cpu_hours", "gpu_time") |
65
+
66
+ ## Understanding Realms
67
+
68
+ XDMoD organizes metrics into different realms:
69
+
70
+ ### Jobs Realm
71
+ Basic job accounting and resource usage metrics:
72
+ - `total_cpu_hours` - Total CPU Hours
73
+ - `job_count` - Number of Jobs Ended
74
+ - `avg_cpu_hours` - Average CPU Hours per Job
75
+ - `total_waitduration_hours` - Total Wait Duration Hours
76
+ - `avg_waitduration_hours` - Average Wait Duration Hours
77
+ - `max_processors` - Maximum Processor Count
78
+ - `total_ace` - ACCESS Credit Equivalents Charged
79
+ - `utilization` - ACCESS CPU Utilization
80
+
81
+ ### SUPREMM Realm
82
+ Detailed performance analytics and system metrics:
83
+ - `gpu_time` - GPU Hours: Total
84
+ - `avg_percent_gpu_usage` - Avg GPU usage
85
+ - `wall_time` - CPU Hours: Total
86
+ - `cpu_time_user` - CPU Hours: User: Total
87
+ - `avg_percent_cpu_user` - Avg CPU %: User
88
+ - `avg_flops_per_core` - Avg FLOPS: Per Core
89
+ - `avg_memory_per_core` - Avg Memory: Per Core
90
+ - `avg_ib_rx_bytes` - Avg InfiniBand rate: Per Node
91
+
92
+ **Note:** For GPU metrics, always use the SUPREMM realm.
93
+
94
+ ## Installation
95
+
96
+ ```bash
97
+ npm install -g @access-mcp/xdmod
98
+ ```
99
+
100
+ ## Configuration
101
+
102
+ ```json
103
+ {
104
+ "mcpServers": {
105
+ "xdmod": {
106
+ "command": "npx",
107
+ "args": ["@access-mcp/xdmod"]
108
+ }
109
+ }
110
+ }
111
+ ```
112
+
113
+ No authentication required - the server accesses publicly available system-wide metrics data.
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Integration tests for the XDMoD MCP server.
3
+ * These tests call the real XDMoD API (public endpoints only).
4
+ * Run with: npx vitest run packages/xdmod/src/__tests__/server.integration.test.ts
5
+ */
6
+ import { describe, test, expect, vi, beforeAll } from "vitest";
7
+ // Prevent process.exit from killing vitest
8
+ vi.spyOn(process, "exit").mockImplementation((() => { }));
9
+ // Mock the base server so we can instantiate without starting HTTP
10
+ vi.mock("@access-mcp/shared", () => ({
11
+ BaseAccessServer: class MockBaseAccessServer {
12
+ serverName;
13
+ version;
14
+ baseURL;
15
+ constructor(serverName, version, baseURL) {
16
+ this.serverName = serverName;
17
+ this.version = version;
18
+ this.baseURL = baseURL;
19
+ }
20
+ httpClient = { get: vi.fn() };
21
+ async start() { }
22
+ },
23
+ handleApiError: vi.fn((error) => error instanceof Error ? error.message : "Unknown error"),
24
+ }));
25
+ const { XDMoDMetricsServer } = await import("../index.js");
26
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
27
+ function getText(result) {
28
+ return result.content[0]?.text ?? "";
29
+ }
30
+ describe("XDMoD Integration Tests (live API)", () => {
31
+ let server;
32
+ beforeAll(() => {
33
+ server = new XDMoDMetricsServer();
34
+ });
35
+ describe("describe_realms", () => {
36
+ test("should return realms from live API", async () => {
37
+ const result = await server["handleToolCall"]({
38
+ method: "tools/call",
39
+ params: { name: "describe_realms", arguments: {} },
40
+ });
41
+ const text = getText(result);
42
+ expect(text).toContain("Jobs");
43
+ expect(text).toContain("Statistics");
44
+ }, 15000);
45
+ });
46
+ describe("describe_fields", () => {
47
+ test("should return Jobs realm fields from live API", async () => {
48
+ const result = await server["handleToolCall"]({
49
+ method: "tools/call",
50
+ params: { name: "describe_fields", arguments: { realm: "Jobs" } },
51
+ });
52
+ const text = getText(result);
53
+ expect(text).toContain("resource");
54
+ expect(text).toContain("total_cpu_hours");
55
+ }, 15000);
56
+ });
57
+ describe("get_dimension_values", () => {
58
+ test("should return resource values from live API", async () => {
59
+ const result = await server["handleToolCall"]({
60
+ method: "tools/call",
61
+ params: {
62
+ name: "get_dimension_values",
63
+ arguments: { realm: "Jobs", dimension: "resource", limit: 10 },
64
+ },
65
+ });
66
+ const text = getText(result);
67
+ expect(text).toContain("resource values in Jobs");
68
+ // Should have at least one resource
69
+ expect(text).not.toContain("No values found");
70
+ }, 15000);
71
+ });
72
+ describe("get_chart_data", () => {
73
+ test("should return chart data from live API", async () => {
74
+ const result = await server["handleToolCall"]({
75
+ method: "tools/call",
76
+ params: {
77
+ name: "get_chart_data",
78
+ arguments: {
79
+ realm: "Jobs",
80
+ group_by: "none",
81
+ statistic: "total_cpu_hours",
82
+ start_date: "2024-01-01",
83
+ end_date: "2024-01-31",
84
+ },
85
+ },
86
+ });
87
+ const text = getText(result);
88
+ expect(text).toContain("Chart Data for total_cpu_hours");
89
+ }, 15000);
90
+ });
91
+ });
@@ -0,0 +1 @@
1
+ export {};