@access-mcp/system-status 0.2.3 → 0.4.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 +154 -8
- package/dist/__tests__/server.integration.test.d.ts +1 -0
- package/dist/__tests__/server.integration.test.js +225 -0
- package/dist/__tests__/server.test.d.ts +1 -0
- package/dist/__tests__/server.test.js +380 -0
- package/dist/index.js +2 -2
- package/dist/server.d.ts +29 -1
- package/dist/server.js +349 -133
- package/dist/web-server.js +23 -23
- package/package.json +17 -2
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# System Status MCP Server
|
|
2
2
|
|
|
3
3
|
MCP server providing real-time system status information for ACCESS-CI resources.
|
|
4
4
|
|
|
@@ -9,28 +9,71 @@ This server provides critical operational information about ACCESS-CI systems, i
|
|
|
9
9
|
## Tools
|
|
10
10
|
|
|
11
11
|
### get_current_outages
|
|
12
|
+
|
|
12
13
|
Get current system outages and issues affecting ACCESS-CI resources.
|
|
13
14
|
|
|
14
15
|
**Parameters:**
|
|
16
|
+
|
|
15
17
|
- `resource_filter` (string, optional): Filter by specific resource name or ID
|
|
16
18
|
|
|
19
|
+
**Returns:**
|
|
20
|
+
- Total outages count and severity breakdown
|
|
21
|
+
- Affected resources list
|
|
22
|
+
- Enhanced outage details with severity levels
|
|
23
|
+
|
|
17
24
|
### get_scheduled_maintenance
|
|
25
|
+
|
|
18
26
|
Get scheduled maintenance and future outages for ACCESS-CI resources.
|
|
19
27
|
|
|
20
28
|
**Parameters:**
|
|
29
|
+
|
|
21
30
|
- `resource_filter` (string, optional): Filter by specific resource name or ID
|
|
22
31
|
|
|
32
|
+
**Returns:**
|
|
33
|
+
- Scheduled maintenance sorted by start time
|
|
34
|
+
- Time until maintenance starts
|
|
35
|
+
- Duration calculations for planned windows
|
|
36
|
+
|
|
37
|
+
### get_past_outages
|
|
38
|
+
|
|
39
|
+
Get historical outages and past incidents affecting ACCESS-CI resources.
|
|
40
|
+
|
|
41
|
+
**Parameters:**
|
|
42
|
+
|
|
43
|
+
- `resource_filter` (string, optional): Filter by specific resource name or ID
|
|
44
|
+
- `limit` (number, optional): Maximum number of past outages to return (default: 100)
|
|
45
|
+
|
|
46
|
+
**Returns:**
|
|
47
|
+
- Historical outage data with duration analysis
|
|
48
|
+
- Recent outages (last 30 days) summary
|
|
49
|
+
- Outage type categorization
|
|
50
|
+
|
|
23
51
|
### get_system_announcements
|
|
24
|
-
|
|
52
|
+
|
|
53
|
+
Get comprehensive system announcements combining current, scheduled, and recent past outages.
|
|
25
54
|
|
|
26
55
|
**Parameters:**
|
|
56
|
+
|
|
27
57
|
- `limit` (number, optional): Maximum number of announcements to return (default: 50)
|
|
28
58
|
|
|
29
|
-
|
|
30
|
-
|
|
59
|
+
**Returns:**
|
|
60
|
+
- Unified view of current outages, scheduled maintenance, and recent past incidents
|
|
61
|
+
- Categorized announcements for better organization
|
|
62
|
+
- Timeline-based sorting
|
|
63
|
+
|
|
64
|
+
### check_resource_status
|
|
65
|
+
|
|
66
|
+
Check the operational status of specific ACCESS-CI resources.
|
|
31
67
|
|
|
32
68
|
**Parameters:**
|
|
33
|
-
|
|
69
|
+
|
|
70
|
+
- `resource_ids` (array): List of resource IDs or names to check status for
|
|
71
|
+
- `use_group_api` (boolean, optional): Use resource group API for more efficient querying (default: false)
|
|
72
|
+
|
|
73
|
+
**Returns:**
|
|
74
|
+
- Operational status for each requested resource
|
|
75
|
+
- Active outage details with severity levels
|
|
76
|
+
- API method used (direct vs group-specific)
|
|
34
77
|
|
|
35
78
|
## Resources
|
|
36
79
|
|
|
@@ -42,7 +85,7 @@ Get the current operational status of a specific resource.
|
|
|
42
85
|
npm install -g @access-mcp/system-status
|
|
43
86
|
```
|
|
44
87
|
|
|
45
|
-
##
|
|
88
|
+
## Configuration
|
|
46
89
|
|
|
47
90
|
Add to your Claude Desktop configuration:
|
|
48
91
|
|
|
@@ -50,16 +93,119 @@ Add to your Claude Desktop configuration:
|
|
|
50
93
|
{
|
|
51
94
|
"mcpServers": {
|
|
52
95
|
"access-system-status": {
|
|
53
|
-
"command": "
|
|
96
|
+
"command": "npx",
|
|
97
|
+
"args": ["@access-mcp/system-status"]
|
|
54
98
|
}
|
|
55
99
|
}
|
|
56
100
|
}
|
|
57
101
|
```
|
|
58
102
|
|
|
103
|
+
## Usage Examples
|
|
104
|
+
|
|
105
|
+
### 🚨 **Monitor Current Issues**
|
|
106
|
+
|
|
107
|
+
- "Are there any current outages on ACCESS-CI?"
|
|
108
|
+
- "Is Delta currently operational?"
|
|
109
|
+
- "What systems are experiencing issues right now?"
|
|
110
|
+
|
|
111
|
+
### 🔧 **Track Maintenance Windows**
|
|
112
|
+
|
|
113
|
+
- "When is the next maintenance for Expanse?"
|
|
114
|
+
- "Show me all scheduled maintenance for this week"
|
|
115
|
+
- "Is there upcoming maintenance on Bridges-2?"
|
|
116
|
+
|
|
117
|
+
### 📢 **System Announcements**
|
|
118
|
+
|
|
119
|
+
- "What are the latest system announcements?"
|
|
120
|
+
- "Are there any important notices for ACCESS users?"
|
|
121
|
+
- "Show me recent updates about system changes"
|
|
122
|
+
|
|
123
|
+
### ✅ **Check Resource Status**
|
|
124
|
+
|
|
125
|
+
- "What's the current status of Anvil?"
|
|
126
|
+
- "Is Frontera available for job submission?"
|
|
127
|
+
- "Check if all GPU systems are operational"
|
|
128
|
+
|
|
129
|
+
## Detailed Usage Examples
|
|
130
|
+
|
|
131
|
+
### Checking Current Outages
|
|
132
|
+
|
|
133
|
+
**Natural Language**: "Are there any systems down right now?"
|
|
134
|
+
|
|
135
|
+
**Tool Call**:
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
const outages = await get_current_outages();
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Returns**: List of active outages with:
|
|
142
|
+
|
|
143
|
+
- Affected resources
|
|
144
|
+
- Start time and expected resolution
|
|
145
|
+
- Impact description
|
|
146
|
+
- Workaround information if available
|
|
147
|
+
|
|
148
|
+
### Finding Scheduled Maintenance
|
|
149
|
+
|
|
150
|
+
**Natural Language**: "When is Delta scheduled for maintenance?"
|
|
151
|
+
|
|
152
|
+
**Tool Call**:
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
const maintenance = await get_scheduled_maintenance({
|
|
156
|
+
resource_filter: "delta",
|
|
157
|
+
});
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**Returns**: Upcoming maintenance windows including:
|
|
161
|
+
|
|
162
|
+
- Scheduled start and end times
|
|
163
|
+
- Systems affected
|
|
164
|
+
- Type of maintenance
|
|
165
|
+
- Expected impact on users
|
|
166
|
+
|
|
167
|
+
### Getting System Announcements
|
|
168
|
+
|
|
169
|
+
**Natural Language**: "What are the latest announcements?"
|
|
170
|
+
|
|
171
|
+
**Tool Call**:
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
const announcements = await get_system_announcements({
|
|
175
|
+
limit: 10,
|
|
176
|
+
});
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**Returns**: Recent announcements about:
|
|
180
|
+
|
|
181
|
+
- Policy changes
|
|
182
|
+
- New features or services
|
|
183
|
+
- Important deadlines
|
|
184
|
+
- System-wide updates
|
|
185
|
+
|
|
186
|
+
### Checking Specific Resource Status
|
|
187
|
+
|
|
188
|
+
**Natural Language**: "Is Expanse available?"
|
|
189
|
+
|
|
190
|
+
**Tool Call**:
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
const status = await get_resource_status({
|
|
194
|
+
resource_id: "expanse.sdsc.xsede.org",
|
|
195
|
+
});
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
**Returns**: Current operational status:
|
|
199
|
+
|
|
200
|
+
- Overall system health
|
|
201
|
+
- Service availability
|
|
202
|
+
- Performance metrics
|
|
203
|
+
- Any active issues or limitations
|
|
204
|
+
|
|
59
205
|
## API Endpoints
|
|
60
206
|
|
|
61
207
|
This server connects to the ACCESS-CI Operations API at `https://operations-api.access-ci.org`
|
|
62
208
|
|
|
63
209
|
## License
|
|
64
210
|
|
|
65
|
-
MIT
|
|
211
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from "vitest";
|
|
2
|
+
import { SystemStatusServer } from "../server.js";
|
|
3
|
+
describe("SystemStatusServer Integration Tests", () => {
|
|
4
|
+
let server;
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
server = new SystemStatusServer();
|
|
7
|
+
});
|
|
8
|
+
describe("Real API Integration", () => {
|
|
9
|
+
it("should fetch current outages from real API", async () => {
|
|
10
|
+
const result = await server["handleToolCall"]({
|
|
11
|
+
params: {
|
|
12
|
+
name: "get_current_outages",
|
|
13
|
+
arguments: { limit: 5 }
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
const responseData = JSON.parse(result.content[0].text);
|
|
17
|
+
expect(responseData).toHaveProperty("total_outages");
|
|
18
|
+
expect(responseData).toHaveProperty("affected_resources");
|
|
19
|
+
expect(responseData).toHaveProperty("severity_counts");
|
|
20
|
+
expect(responseData.severity_counts).toHaveProperty("high");
|
|
21
|
+
expect(responseData.severity_counts).toHaveProperty("medium");
|
|
22
|
+
expect(responseData.severity_counts).toHaveProperty("low");
|
|
23
|
+
expect(responseData.severity_counts).toHaveProperty("unknown");
|
|
24
|
+
expect(Array.isArray(responseData.outages)).toBe(true);
|
|
25
|
+
// Check enhanced fields
|
|
26
|
+
if (responseData.outages.length > 0) {
|
|
27
|
+
const outage = responseData.outages[0];
|
|
28
|
+
expect(outage).toHaveProperty("severity");
|
|
29
|
+
expect(outage).toHaveProperty("posted_time");
|
|
30
|
+
expect(outage).toHaveProperty("last_updated");
|
|
31
|
+
}
|
|
32
|
+
}, 10000);
|
|
33
|
+
it("should fetch scheduled maintenance from real API", async () => {
|
|
34
|
+
const result = await server["handleToolCall"]({
|
|
35
|
+
params: {
|
|
36
|
+
name: "get_scheduled_maintenance",
|
|
37
|
+
arguments: { limit: 5 }
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
const responseData = JSON.parse(result.content[0].text);
|
|
41
|
+
expect(responseData).toHaveProperty("total_scheduled");
|
|
42
|
+
expect(responseData).toHaveProperty("upcoming_24h");
|
|
43
|
+
expect(responseData).toHaveProperty("upcoming_week");
|
|
44
|
+
expect(responseData).toHaveProperty("affected_resources");
|
|
45
|
+
expect(Array.isArray(responseData.maintenance)).toBe(true);
|
|
46
|
+
// Check enhanced fields
|
|
47
|
+
if (responseData.maintenance.length > 0) {
|
|
48
|
+
const maintenance = responseData.maintenance[0];
|
|
49
|
+
expect(maintenance).toHaveProperty("hours_until_start");
|
|
50
|
+
expect(maintenance).toHaveProperty("has_scheduled_time");
|
|
51
|
+
expect(maintenance.hours_until_start).toSatisfy((val) => val === null || typeof val === "number");
|
|
52
|
+
}
|
|
53
|
+
}, 10000);
|
|
54
|
+
it("should fetch past outages from real API", async () => {
|
|
55
|
+
const result = await server["handleToolCall"]({
|
|
56
|
+
params: {
|
|
57
|
+
name: "get_past_outages",
|
|
58
|
+
arguments: { limit: 10 }
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
const responseData = JSON.parse(result.content[0].text);
|
|
62
|
+
expect(responseData).toHaveProperty("total_past_outages");
|
|
63
|
+
expect(responseData).toHaveProperty("recent_outages_30_days");
|
|
64
|
+
expect(responseData).toHaveProperty("affected_resources");
|
|
65
|
+
expect(responseData).toHaveProperty("outage_types");
|
|
66
|
+
expect(responseData).toHaveProperty("average_duration_hours");
|
|
67
|
+
expect(Array.isArray(responseData.outages)).toBe(true);
|
|
68
|
+
// Check enhanced fields
|
|
69
|
+
if (responseData.outages.length > 0) {
|
|
70
|
+
const outage = responseData.outages[0];
|
|
71
|
+
expect(outage).toHaveProperty("duration_hours");
|
|
72
|
+
expect(outage).toHaveProperty("days_ago");
|
|
73
|
+
expect(outage).toHaveProperty("outage_type");
|
|
74
|
+
expect(outage.days_ago).toSatisfy((val) => val === null || typeof val === "number");
|
|
75
|
+
}
|
|
76
|
+
}, 10000);
|
|
77
|
+
it("should get comprehensive system announcements", async () => {
|
|
78
|
+
const result = await server["handleToolCall"]({
|
|
79
|
+
params: {
|
|
80
|
+
name: "get_system_announcements",
|
|
81
|
+
arguments: { limit: 20 }
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
const responseData = JSON.parse(result.content[0].text);
|
|
85
|
+
expect(responseData).toHaveProperty("total_announcements");
|
|
86
|
+
expect(responseData).toHaveProperty("current_outages");
|
|
87
|
+
expect(responseData).toHaveProperty("scheduled_maintenance");
|
|
88
|
+
expect(responseData).toHaveProperty("recent_past_outages");
|
|
89
|
+
expect(responseData).toHaveProperty("categories");
|
|
90
|
+
expect(responseData.categories).toHaveProperty("current");
|
|
91
|
+
expect(responseData.categories).toHaveProperty("scheduled");
|
|
92
|
+
expect(responseData.categories).toHaveProperty("recent_past");
|
|
93
|
+
expect(Array.isArray(responseData.announcements)).toBe(true);
|
|
94
|
+
// Check categorization
|
|
95
|
+
if (responseData.announcements.length > 0) {
|
|
96
|
+
const announcement = responseData.announcements[0];
|
|
97
|
+
expect(announcement).toHaveProperty("category");
|
|
98
|
+
expect(["current", "scheduled", "recent_past"]).toContain(announcement.category);
|
|
99
|
+
}
|
|
100
|
+
}, 15000);
|
|
101
|
+
it("should check resource status with direct method", async () => {
|
|
102
|
+
// Test with common resource names that might exist
|
|
103
|
+
const result = await server["handleToolCall"]({
|
|
104
|
+
params: {
|
|
105
|
+
name: "check_resource_status",
|
|
106
|
+
arguments: {
|
|
107
|
+
resource_ids: ["anvil", "bridges", "jetstream"],
|
|
108
|
+
use_group_api: false
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
const responseData = JSON.parse(result.content[0].text);
|
|
113
|
+
expect(responseData).toHaveProperty("checked_at");
|
|
114
|
+
expect(responseData).toHaveProperty("resources_checked", 3);
|
|
115
|
+
expect(responseData).toHaveProperty("operational");
|
|
116
|
+
expect(responseData).toHaveProperty("affected");
|
|
117
|
+
expect(responseData).toHaveProperty("api_method", "direct_outages_check");
|
|
118
|
+
expect(Array.isArray(responseData.resource_status)).toBe(true);
|
|
119
|
+
expect(responseData.resource_status).toHaveLength(3);
|
|
120
|
+
// Check resource status structure
|
|
121
|
+
responseData.resource_status.forEach((resource) => {
|
|
122
|
+
expect(resource).toHaveProperty("resource_id");
|
|
123
|
+
expect(resource).toHaveProperty("status");
|
|
124
|
+
expect(["operational", "affected"]).toContain(resource.status);
|
|
125
|
+
expect(resource).toHaveProperty("active_outages");
|
|
126
|
+
expect(Array.isArray(resource.outage_details)).toBe(true);
|
|
127
|
+
});
|
|
128
|
+
}, 10000);
|
|
129
|
+
it("should test group API functionality", async () => {
|
|
130
|
+
// Test group API with a resource that might have a group ID
|
|
131
|
+
const result = await server["handleToolCall"]({
|
|
132
|
+
params: {
|
|
133
|
+
name: "check_resource_status",
|
|
134
|
+
arguments: {
|
|
135
|
+
resource_ids: ["anvil"],
|
|
136
|
+
use_group_api: true
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
const responseData = JSON.parse(result.content[0].text);
|
|
141
|
+
expect(responseData).toHaveProperty("api_method", "resource_group_api");
|
|
142
|
+
expect(responseData).toHaveProperty("resources_checked", 1);
|
|
143
|
+
expect(responseData.resource_status).toHaveLength(1);
|
|
144
|
+
const resourceStatus = responseData.resource_status[0];
|
|
145
|
+
expect(resourceStatus).toHaveProperty("resource_id", "anvil");
|
|
146
|
+
expect(resourceStatus).toHaveProperty("api_method");
|
|
147
|
+
expect(["group_specific", "group_specific_failed"]).toContain(resourceStatus.api_method);
|
|
148
|
+
// If it succeeded, check structure
|
|
149
|
+
if (resourceStatus.api_method === "group_specific") {
|
|
150
|
+
expect(resourceStatus).toHaveProperty("status");
|
|
151
|
+
expect(["operational", "affected"]).toContain(resourceStatus.status);
|
|
152
|
+
}
|
|
153
|
+
// If it failed, check error handling
|
|
154
|
+
if (resourceStatus.api_method === "group_specific_failed") {
|
|
155
|
+
expect(resourceStatus.status).toBe("unknown");
|
|
156
|
+
expect(resourceStatus).toHaveProperty("error");
|
|
157
|
+
}
|
|
158
|
+
}, 10000);
|
|
159
|
+
it("should filter outages by resource correctly", async () => {
|
|
160
|
+
const result = await server["handleToolCall"]({
|
|
161
|
+
params: {
|
|
162
|
+
name: "get_current_outages",
|
|
163
|
+
arguments: { resource_filter: "anvil" }
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
const responseData = JSON.parse(result.content[0].text);
|
|
167
|
+
expect(responseData).toHaveProperty("total_outages");
|
|
168
|
+
// If there are any results, they should match the filter
|
|
169
|
+
responseData.outages.forEach((outage) => {
|
|
170
|
+
const matchesFilter = outage.Subject?.toLowerCase().includes("anvil") ||
|
|
171
|
+
outage.AffectedResources?.some((resource) => resource.ResourceName?.toLowerCase().includes("anvil") ||
|
|
172
|
+
resource.ResourceID?.toString().includes("anvil"));
|
|
173
|
+
expect(matchesFilter).toBe(true);
|
|
174
|
+
});
|
|
175
|
+
}, 10000);
|
|
176
|
+
it("should handle resource reads for all endpoints", async () => {
|
|
177
|
+
const resources = [
|
|
178
|
+
"accessci://system-status",
|
|
179
|
+
"accessci://outages/current",
|
|
180
|
+
"accessci://outages/scheduled",
|
|
181
|
+
"accessci://outages/past"
|
|
182
|
+
];
|
|
183
|
+
for (const uri of resources) {
|
|
184
|
+
const result = await server["handleResourceRead"]({
|
|
185
|
+
params: { uri }
|
|
186
|
+
});
|
|
187
|
+
expect(result.contents).toHaveLength(1);
|
|
188
|
+
expect(result.contents[0]).toHaveProperty("uri", uri);
|
|
189
|
+
expect(result.contents[0]).toHaveProperty("mimeType");
|
|
190
|
+
expect(result.contents[0]).toHaveProperty("text");
|
|
191
|
+
if (uri !== "accessci://system-status") {
|
|
192
|
+
// JSON resources should have valid JSON
|
|
193
|
+
expect(() => JSON.parse(result.contents[0].text)).not.toThrow();
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}, 15000);
|
|
197
|
+
});
|
|
198
|
+
describe("Edge Cases and Error Handling", () => {
|
|
199
|
+
it("should handle empty API responses", async () => {
|
|
200
|
+
// This tests the robustness of our logic with potentially empty responses
|
|
201
|
+
const result = await server["handleToolCall"]({
|
|
202
|
+
params: {
|
|
203
|
+
name: "get_current_outages",
|
|
204
|
+
arguments: { resource_filter: "nonexistent-resource-xyz" }
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
const responseData = JSON.parse(result.content[0].text);
|
|
208
|
+
expect(responseData).toHaveProperty("total_outages", 0);
|
|
209
|
+
expect(responseData.outages).toHaveLength(0);
|
|
210
|
+
expect(responseData.affected_resources).toHaveLength(0);
|
|
211
|
+
}, 10000);
|
|
212
|
+
it("should handle large limit values gracefully", async () => {
|
|
213
|
+
const result = await server["handleToolCall"]({
|
|
214
|
+
params: {
|
|
215
|
+
name: "get_past_outages",
|
|
216
|
+
arguments: { limit: 1000 }
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
const responseData = JSON.parse(result.content[0].text);
|
|
220
|
+
expect(responseData).toHaveProperty("total_past_outages");
|
|
221
|
+
// Should not crash or timeout
|
|
222
|
+
expect(responseData.outages.length).toBeLessThanOrEqual(1000);
|
|
223
|
+
}, 15000);
|
|
224
|
+
});
|
|
225
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|