@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 CHANGED
@@ -1,4 +1,4 @@
1
- # ACCESS-CI System Status MCP Server
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
- Get all system announcements (current and scheduled).
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
- ### get_resource_status
30
- Get the current operational status of a specific resource.
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
- - `resource_id` (string): The resource ID to check status for
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
- ## Usage
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": "access-mcp-system-status"
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 {};