zephyr-enterprise-tools 1.2.1 → 1.2.3
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 +26 -30
- package/mcp-server.js +29 -0
- package/package.json +1 -1
- package/zephyr-enterprise-tools.js +93 -0
package/README.md
CHANGED
|
@@ -73,50 +73,46 @@ Use zephyr-enterprise-tools as an MCP (Model Context Protocol) server with your
|
|
|
73
73
|
| `search_test_cases` | Search test cases by query |
|
|
74
74
|
| `user_activity` | Get user activity metrics |
|
|
75
75
|
|
|
76
|
-
###
|
|
76
|
+
### Claude Desktop
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
Edit your `claude_desktop_config.json` file:
|
|
79
79
|
|
|
80
80
|
```json
|
|
81
81
|
{
|
|
82
|
-
"
|
|
83
|
-
"zephyr
|
|
84
|
-
"type": "stdio",
|
|
82
|
+
"mcpServers": {
|
|
83
|
+
"zephyr": {
|
|
85
84
|
"command": "npx",
|
|
86
|
-
"args": [
|
|
85
|
+
"args": [
|
|
86
|
+
"-y",
|
|
87
|
+
"--package",
|
|
88
|
+
"zephyr-enterprise-tools@latest",
|
|
89
|
+
"zephyr-mcp"
|
|
90
|
+
],
|
|
87
91
|
"env": {
|
|
88
|
-
"ZEPHYR_BASE_URL": "
|
|
89
|
-
"ZEPHYR_TOKEN": "
|
|
92
|
+
"ZEPHYR_BASE_URL": "https://your-zephyr.com/flex/services/rest/latest",
|
|
93
|
+
"ZEPHYR_TOKEN": "your-api-token"
|
|
90
94
|
}
|
|
91
95
|
}
|
|
92
|
-
}
|
|
93
|
-
"inputs": [
|
|
94
|
-
{
|
|
95
|
-
"id": "zephyr_base_url",
|
|
96
|
-
"type": "promptString",
|
|
97
|
-
"description": "Zephyr Enterprise API Base URL (e.g. https://your-zephyr.com/flex/services/rest/latest)",
|
|
98
|
-
"password": false
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
"id": "zephyr_token",
|
|
102
|
-
"type": "promptString",
|
|
103
|
-
"description": "Zephyr Enterprise API Token",
|
|
104
|
-
"password": true
|
|
105
|
-
}
|
|
106
|
-
]
|
|
96
|
+
}
|
|
107
97
|
}
|
|
108
98
|
```
|
|
109
99
|
|
|
110
|
-
###
|
|
100
|
+
### VS Code with GitHub Copilot
|
|
111
101
|
|
|
112
|
-
|
|
102
|
+
Create or edit `.vscode/mcp.json` in your workspace:
|
|
113
103
|
|
|
114
104
|
```json
|
|
115
105
|
{
|
|
116
|
-
"
|
|
117
|
-
"zephyr
|
|
106
|
+
"servers": {
|
|
107
|
+
"zephyr": {
|
|
108
|
+
"type": "stdio",
|
|
118
109
|
"command": "npx",
|
|
119
|
-
"args": [
|
|
110
|
+
"args": [
|
|
111
|
+
"-y",
|
|
112
|
+
"--package",
|
|
113
|
+
"zephyr-enterprise-tools",
|
|
114
|
+
"zephyr-mcp"
|
|
115
|
+
],
|
|
120
116
|
"env": {
|
|
121
117
|
"ZEPHYR_BASE_URL": "https://your-zephyr.com/flex/services/rest/latest",
|
|
122
118
|
"ZEPHYR_TOKEN": "your-api-token"
|
|
@@ -126,9 +122,9 @@ Add to your `mcp.json` configuration:
|
|
|
126
122
|
}
|
|
127
123
|
```
|
|
128
124
|
|
|
129
|
-
###
|
|
125
|
+
### Cursor
|
|
130
126
|
|
|
131
|
-
|
|
127
|
+
Add to your `mcp.json` configuration:
|
|
132
128
|
|
|
133
129
|
```json
|
|
134
130
|
{
|
package/mcp-server.js
CHANGED
|
@@ -167,6 +167,23 @@ const TOOLS = [
|
|
|
167
167
|
required: ['projectId', 'releaseId'],
|
|
168
168
|
},
|
|
169
169
|
},
|
|
170
|
+
{
|
|
171
|
+
name: 'user_trend',
|
|
172
|
+
description: 'Get full audit log activity for a user — every action they performed across the system. Filter by date range and optionally by entity type (project or release).',
|
|
173
|
+
inputSchema: {
|
|
174
|
+
type: 'object',
|
|
175
|
+
properties: {
|
|
176
|
+
userName: { type: 'string', description: 'Username to look up (e.g. "dylan.garcia")' },
|
|
177
|
+
fromDate: { type: 'string', description: 'Start date YYYY-MM-DD (e.g. "2026-08-01")' },
|
|
178
|
+
toDate: { type: 'string', description: 'End date YYYY-MM-DD (e.g. "2026-08-18")' },
|
|
179
|
+
entity: { type: 'string', description: 'Filter by entity type: "project", "release", or "" for all', enum: ['project', 'release', ''] },
|
|
180
|
+
operation: { type: 'string', description: 'Filter by operation (e.g. "CREATE", "UPDATE"). Omit for all.' },
|
|
181
|
+
offset: { type: 'number', description: 'Pagination offset (default 0)' },
|
|
182
|
+
pageSize: { type: 'number', description: 'Records per page (default 25)' },
|
|
183
|
+
},
|
|
184
|
+
required: ['userName'],
|
|
185
|
+
},
|
|
186
|
+
},
|
|
170
187
|
{
|
|
171
188
|
name: 'list_projects',
|
|
172
189
|
description: 'List all available Zephyr projects.',
|
|
@@ -282,6 +299,18 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
282
299
|
case 'user_activity':
|
|
283
300
|
result = await tools.getUserActivity(projectId, releaseId, { days: args.days || 30 });
|
|
284
301
|
break;
|
|
302
|
+
|
|
303
|
+
case 'user_trend':
|
|
304
|
+
result = await tools.getUserTrend({
|
|
305
|
+
userName: args.userName,
|
|
306
|
+
fromDate: args.fromDate || null,
|
|
307
|
+
toDate: args.toDate || null,
|
|
308
|
+
entity: args.entity || '',
|
|
309
|
+
operation: args.operation || null,
|
|
310
|
+
offset: args.offset || 0,
|
|
311
|
+
pageSize: args.pageSize || 25,
|
|
312
|
+
});
|
|
313
|
+
break;
|
|
285
314
|
|
|
286
315
|
case 'list_projects':
|
|
287
316
|
const projects = await tools.GET('/project');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zephyr-enterprise-tools",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.3",
|
|
4
4
|
"description": "Comprehensive Zephyr Enterprise Tools - Release Readiness, Project Health, Test Analytics & More",
|
|
5
5
|
"main": "zephyr-enterprise-tools.js",
|
|
6
6
|
"types": "zephyr-enterprise-tools.d.ts",
|
|
@@ -1285,6 +1285,99 @@ export class QualityGates {
|
|
|
1285
1285
|
topExecutors: executors.slice(0, 5),
|
|
1286
1286
|
};
|
|
1287
1287
|
}
|
|
1288
|
+
|
|
1289
|
+
// ─── User Trend (Audit Logs) ─────────────────────────────────────────────────
|
|
1290
|
+
|
|
1291
|
+
async getUserTrend(options = {}) {
|
|
1292
|
+
const {
|
|
1293
|
+
userName = "",
|
|
1294
|
+
fromDate = null, // "YYYY-MM-DD"
|
|
1295
|
+
toDate = null, // "YYYY-MM-DD"
|
|
1296
|
+
entity = "", // "project", "release", or "" for all
|
|
1297
|
+
operation = null, // specific operation or null for all
|
|
1298
|
+
offset = 0,
|
|
1299
|
+
pageSize = 25,
|
|
1300
|
+
} = options;
|
|
1301
|
+
|
|
1302
|
+
const v3BaseUrl = this.baseUrl.replace('/latest', '/v3');
|
|
1303
|
+
const url = new URL(`${v3BaseUrl}/ui/auditLogs`);
|
|
1304
|
+
url.searchParams.set("offset", String(offset));
|
|
1305
|
+
url.searchParams.set("pagesize", String(pageSize));
|
|
1306
|
+
url.searchParams.set("isascorder", "false");
|
|
1307
|
+
url.searchParams.set("order", "id");
|
|
1308
|
+
url.searchParams.set("isExport", "false");
|
|
1309
|
+
|
|
1310
|
+
const body = { entity, operation, userName };
|
|
1311
|
+
|
|
1312
|
+
if (fromDate) {
|
|
1313
|
+
body.fromDate = fromDate;
|
|
1314
|
+
body.fromDateVal = `${fromDate}T00:00:00.000Z`;
|
|
1315
|
+
}
|
|
1316
|
+
if (toDate) {
|
|
1317
|
+
body.toDate = toDate;
|
|
1318
|
+
body.toDateVal = `${toDate}T00:00:00.000Z`;
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
const res = await fetch(url.toString(), {
|
|
1322
|
+
method: "POST",
|
|
1323
|
+
headers: {
|
|
1324
|
+
Accept: "application/json",
|
|
1325
|
+
"Content-Type": "application/json",
|
|
1326
|
+
...this.authHeader(),
|
|
1327
|
+
},
|
|
1328
|
+
body: JSON.stringify(body),
|
|
1329
|
+
});
|
|
1330
|
+
|
|
1331
|
+
if (!res.ok) {
|
|
1332
|
+
const text = await res.text().catch(() => "");
|
|
1333
|
+
throw new Error(`Zephyr audit logs API ${res.status}: ${text}`);
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
const data = await res.json();
|
|
1337
|
+
const logs = data.results || data || [];
|
|
1338
|
+
|
|
1339
|
+
// Summarise by operation and entity type
|
|
1340
|
+
const byOperation = {};
|
|
1341
|
+
const byEntity = {};
|
|
1342
|
+
for (const log of logs) {
|
|
1343
|
+
const op = log.operation || "Unknown";
|
|
1344
|
+
const ent = log.entity || "Unknown";
|
|
1345
|
+
byOperation[op] = (byOperation[op] || 0) + 1;
|
|
1346
|
+
byEntity[ent] = (byEntity[ent] || 0) + 1;
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
return {
|
|
1350
|
+
tool: "User Trend",
|
|
1351
|
+
userName,
|
|
1352
|
+
dateRange: { from: fromDate || "all", to: toDate || "all" },
|
|
1353
|
+
entity: entity || "all",
|
|
1354
|
+
timestamp: new Date().toISOString(),
|
|
1355
|
+
totalRecords: data.totalCount ?? logs.length,
|
|
1356
|
+
offset,
|
|
1357
|
+
pageSize,
|
|
1358
|
+
operationSummary: Object.entries(byOperation)
|
|
1359
|
+
.map(([operation, count]) => ({ operation, count }))
|
|
1360
|
+
.sort((a, b) => b.count - a.count),
|
|
1361
|
+
entitySummary: Object.entries(byEntity)
|
|
1362
|
+
.map(([entity, count]) => ({ entity, count }))
|
|
1363
|
+
.sort((a, b) => b.count - a.count),
|
|
1364
|
+
auditLogs: logs.map(log => ({
|
|
1365
|
+
id: log.id,
|
|
1366
|
+
userName: log.userName,
|
|
1367
|
+
entity: log.entity,
|
|
1368
|
+
entityName: log.entityName,
|
|
1369
|
+
operation: log.operation,
|
|
1370
|
+
description: log.description,
|
|
1371
|
+
detail: log.detail,
|
|
1372
|
+
projectId: log.projectId,
|
|
1373
|
+
projectName: log.projectName,
|
|
1374
|
+
releaseId: log.releaseId,
|
|
1375
|
+
releaseName: log.releaseName,
|
|
1376
|
+
createdOn: log.createdOn,
|
|
1377
|
+
ipAddress: log.ipAddress,
|
|
1378
|
+
})),
|
|
1379
|
+
};
|
|
1380
|
+
}
|
|
1288
1381
|
}
|
|
1289
1382
|
|
|
1290
1383
|
// Export with both names for backward compatibility
|