@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 +113 -0
- package/dist/__tests__/server.integration.test.d.ts +1 -0
- package/dist/__tests__/server.integration.test.js +91 -0
- package/dist/__tests__/server.test.d.ts +1 -0
- package/dist/__tests__/server.test.js +507 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.js +1029 -0
- package/dist/user-specific.d.ts +18 -0
- package/dist/user-specific.js +58 -0
- package/package.json +46 -0
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 {};
|