mcp-insomnia 0.1.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,125 @@
1
+ # MCP-Insomnia
2
+
3
+ MCP-Insomnia is an MCP (Model Context Protocol) server that enables AI agents to create and manage API collections in Insomnia-compatible format. This server provides tools and resources for managing collections, requests, and environments that can be exported to Insomnia.
4
+
5
+ ## Installation
6
+
7
+ ### Prerequisites
8
+
9
+ - Node.js 18+
10
+ - npm or yarn
11
+
12
+ ### Install from NPM
13
+
14
+ ```bash
15
+ npm install -g mcp-insomnia
16
+ ```
17
+
18
+ ### Install from Source
19
+
20
+ ```bash
21
+ git clone https://github.com/anggasct/mcp-insomnia.git
22
+ cd mcp-insomnia
23
+ npm install
24
+ npm run build
25
+ ```
26
+
27
+ ### Add to MCP Configuration
28
+
29
+ Add to your MCP client configuration:
30
+
31
+ ```json
32
+ {
33
+ "mcpServers": {
34
+ "insomnia": {
35
+ "command": "mcp-insomnia"
36
+ }
37
+ }
38
+ }
39
+ ```
40
+
41
+ Or if installed from source:
42
+
43
+ ```json
44
+ {
45
+ "mcpServers": {
46
+ "insomnia": {
47
+ "command": "node",
48
+ "args": ["/path/to/mcp-insomnia/dist/index.js"]
49
+ }
50
+ }
51
+ }
52
+ ```
53
+
54
+ ## Available Tools
55
+
56
+ ### Collection Management
57
+
58
+ - `create_collection` - Create new collection/workspace
59
+ - `list_collections` - List all collections
60
+ - `export_collection` - Export collection to JSON format
61
+ - `import_from_insomnia_export` - Import collections from a standard Insomnia V4 export file
62
+
63
+ ### Folder Management
64
+
65
+ - `create_folder` - Create folder within collection
66
+
67
+ ### Request Management
68
+
69
+ - `create_request_in_collection` - Create new request
70
+ - `update_request` - Update existing request
71
+ - `delete_request` - Delete request
72
+ - `execute_request` - Execute request and view response
73
+
74
+ ### Environment Management
75
+
76
+ - `set_environment_variable` - Set environment variable
77
+ - `get_environment_variables` - Get environment variables
78
+
79
+ ## Available Resources
80
+
81
+ - `insomnia://collections` - List all collections
82
+ - `insomnia://requests` - List all requests. Can be filtered by `?collectionId={id}`.
83
+ - `insomnia://environments` - List environment variables. Can be filtered by `?collectionId={id}`.
84
+ - `insomnia://collection/{id}` - Specific collection details
85
+ - `insomnia://request/{id}` - Specific request details
86
+ - `insomnia://request/{id}/history` - Get the execution history for a specific request
87
+ - `insomnia://search?q={keyword}` - Search across all collections, folders, and requests.
88
+ - `insomnia://stats` - Global statistics
89
+
90
+ ## Usage Examples
91
+
92
+ ### Create Collection
93
+
94
+ ```
95
+ Create a new collection named "API Testing" for testing endpoints
96
+ ```
97
+
98
+ ### Add Request
99
+
100
+ ```
101
+ Add GET request to "API Testing" collection with:
102
+ - Name: Get Users
103
+ - URL: https://jsonplaceholder.typicode.com/users
104
+ - Headers: Content-Type: application/json
105
+ ```
106
+
107
+ ### Set Environment Variable
108
+
109
+ ```
110
+ Set environment variable "baseUrl" with value "https://api.example.com" for "API Testing" collection
111
+ ```
112
+
113
+ ### Execute Request
114
+
115
+ ```
116
+ Execute "Get Users" request using the configured environment variables
117
+ ```
118
+
119
+ ## Data Storage
120
+
121
+ Data is stored in `~/.mcp-insomnia/collections.json` in JSON format.
122
+
123
+ ## License
124
+
125
+ MIT License
@@ -0,0 +1,9 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(npm --prefix .. run build)",
5
+ "Bash(npm:*)"
6
+ ],
7
+ "deny": []
8
+ }
9
+ }
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env node
2
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
+ import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema } from '@modelcontextprotocol/sdk/types.js';
5
+ import { createInsomniaTools } from './tools.js';
6
+ import { createInsomniaResources } from './resources.js';
7
+ const server = new Server({
8
+ name: 'mcp-insomnia',
9
+ version: '0.1.0',
10
+ }, {
11
+ capabilities: {
12
+ tools: {},
13
+ resources: {},
14
+ },
15
+ });
16
+ const tools = createInsomniaTools();
17
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
18
+ return {
19
+ tools: tools.map(tool => ({
20
+ name: tool.name,
21
+ description: tool.description,
22
+ inputSchema: tool.inputSchema,
23
+ })),
24
+ };
25
+ });
26
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
27
+ const { name } = request.params;
28
+ const tool = tools.find(t => t.name === name);
29
+ if (!tool) {
30
+ throw new Error(`Tool ${name} not found`);
31
+ }
32
+ return await tool.handler(request);
33
+ });
34
+ const resources = createInsomniaResources();
35
+ server.setRequestHandler(ListResourcesRequestSchema, async () => {
36
+ return {
37
+ resources: resources.map(resource => ({
38
+ uri: resource.uri,
39
+ name: resource.name,
40
+ description: resource.description,
41
+ mimeType: resource.mimeType,
42
+ })),
43
+ };
44
+ });
45
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
46
+ const { uri } = request.params;
47
+ const resource = resources.find(r => r.uri === uri || uri.startsWith(r.uri.replace('{id}', '')));
48
+ if (!resource) {
49
+ throw new Error(`Resource ${uri} not found`);
50
+ }
51
+ return await resource.handler(request);
52
+ });
53
+ async function main() {
54
+ const transport = new StdioServerTransport();
55
+ await server.connect(transport);
56
+ console.error('MCP Insomnia server running on stdio');
57
+ }
58
+ main().catch((error) => {
59
+ console.error('Server error:', error);
60
+ process.exit(1);
61
+ });
62
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { ReadResourceRequest } from '@modelcontextprotocol/sdk/types.js';
2
+ interface Resource {
3
+ uri: string;
4
+ name: string;
5
+ description: string;
6
+ mimeType: string;
7
+ handler: (request: ReadResourceRequest) => Promise<any>;
8
+ }
9
+ export declare function createInsomniaResources(): Resource[];
10
+ export {};
11
+ //# sourceMappingURL=resources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.d.ts","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAIzE,UAAU,QAAQ;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;CACzD;AAED,wBAAgB,uBAAuB,IAAI,QAAQ,EAAE,CAuepD"}
@@ -0,0 +1,449 @@
1
+ import { storage } from './storage.js';
2
+ export function createInsomniaResources() {
3
+ return [
4
+ {
5
+ uri: 'insomnia://collections',
6
+ name: 'Collections',
7
+ description: 'List all collections with folder structure',
8
+ mimeType: 'application/json',
9
+ handler: async () => {
10
+ const collections = storage.getAllCollections();
11
+ const result = Array.from(collections.entries()).map(([id, structure]) => ({
12
+ id,
13
+ name: structure.workspace.name,
14
+ description: structure.workspace.description,
15
+ scope: structure.workspace.scope,
16
+ created: new Date(structure.workspace.created).toISOString(),
17
+ modified: new Date(structure.workspace.modified).toISOString(),
18
+ folders: structure.folders.map(folder => ({
19
+ id: folder._id,
20
+ name: folder.name,
21
+ description: folder.description,
22
+ parentId: folder.parentId,
23
+ created: new Date(folder.created).toISOString(),
24
+ modified: new Date(folder.modified).toISOString(),
25
+ })),
26
+ requestCount: structure.requests.length,
27
+ environmentCount: structure.environments.length,
28
+ }));
29
+ return {
30
+ contents: [
31
+ {
32
+ type: 'text',
33
+ text: JSON.stringify(result, null, 2),
34
+ },
35
+ ],
36
+ };
37
+ },
38
+ },
39
+ {
40
+ uri: 'insomnia://requests',
41
+ name: 'Requests',
42
+ description: 'List all requests in collections with metadata. Can be filtered with ?collectionId={id}',
43
+ mimeType: 'application/json',
44
+ handler: async (request) => {
45
+ const allRequests = [];
46
+ const uri = request.params.uri;
47
+ const url = new URL(uri);
48
+ const collectionIdFilter = url.searchParams.get('collectionId');
49
+ const collections = collectionIdFilter
50
+ ? new Map([[collectionIdFilter, storage.getCollection(collectionIdFilter)]])
51
+ : storage.getAllCollections();
52
+ for (const [collectionId, structure] of collections.entries()) {
53
+ if (!structure)
54
+ continue; // Skip if a filtered collection is not found
55
+ const requests = structure.requests.map(request => ({
56
+ id: request._id,
57
+ collectionId,
58
+ collectionName: structure.workspace.name,
59
+ parentId: request.parentId,
60
+ parentName: structure.folders.find(f => f._id === request.parentId)?.name ?? 'Root',
61
+ name: request.name,
62
+ description: request.description,
63
+ method: request.method,
64
+ url: request.url,
65
+ hasAuthentication: !!request.authentication,
66
+ headerCount: request.headers?.length || 0,
67
+ parameterCount: request.parameters?.length || 0,
68
+ hasBody: !!request.body,
69
+ created: new Date(request.created).toISOString(),
70
+ modified: new Date(request.modified).toISOString(),
71
+ }));
72
+ allRequests.push(...requests);
73
+ }
74
+ allRequests.sort((a, b) => new Date(b.modified).getTime() - new Date(a.modified).getTime());
75
+ return {
76
+ contents: [
77
+ {
78
+ type: 'text',
79
+ text: JSON.stringify(allRequests, null, 2),
80
+ },
81
+ ],
82
+ };
83
+ },
84
+ },
85
+ {
86
+ uri: 'insomnia://environments',
87
+ name: 'Environments',
88
+ description: 'List environment variables per collection. Can be filtered with ?collectionId={id}',
89
+ mimeType: 'application/json',
90
+ handler: async (request) => {
91
+ const allEnvironments = [];
92
+ const uri = request.params.uri;
93
+ const url = new URL(uri);
94
+ const collectionIdFilter = url.searchParams.get('collectionId');
95
+ const collections = collectionIdFilter
96
+ ? new Map([[collectionIdFilter, storage.getCollection(collectionIdFilter)]])
97
+ : storage.getAllCollections();
98
+ for (const [collectionId, structure] of collections.entries()) {
99
+ if (!structure)
100
+ continue; // Skip if a filtered collection is not found
101
+ const environments = structure.environments.map(env => ({
102
+ id: env._id,
103
+ collectionId,
104
+ collectionName: structure.workspace.name,
105
+ name: env.name,
106
+ description: env.description,
107
+ variableCount: Object.keys(env.data || {}).length,
108
+ variables: Object.entries(env.data || {}).map(([key, value]) => ({
109
+ key,
110
+ value: typeof value === 'string' && value.length > 100 ? `${value.substring(0, 100)}...` : value,
111
+ type: typeof value,
112
+ })),
113
+ isPrivate: env.isPrivate || false,
114
+ created: new Date(env.created).toISOString(),
115
+ modified: new Date(env.modified).toISOString(),
116
+ }));
117
+ allEnvironments.push(...environments);
118
+ }
119
+ return {
120
+ contents: [
121
+ {
122
+ type: 'text',
123
+ text: JSON.stringify(allEnvironments, null, 2),
124
+ },
125
+ ],
126
+ };
127
+ },
128
+ },
129
+ {
130
+ uri: 'insomnia://collection/{id}',
131
+ name: 'Collection Detail',
132
+ description: 'Full details of a specific collection',
133
+ mimeType: 'application/json',
134
+ handler: async (request) => {
135
+ const uri = request.params.uri;
136
+ const collectionId = uri.replace('insomnia://collection/', '');
137
+ const structure = storage.getCollection(collectionId);
138
+ if (!structure) {
139
+ throw new Error(`Collection with ID ${collectionId} not found`);
140
+ }
141
+ const result = {
142
+ workspace: {
143
+ id: structure.workspace._id,
144
+ name: structure.workspace.name,
145
+ description: structure.workspace.description,
146
+ scope: structure.workspace.scope,
147
+ created: new Date(structure.workspace.created).toISOString(),
148
+ modified: new Date(structure.workspace.modified).toISOString(),
149
+ },
150
+ structure: {
151
+ folders: structure.folders.map(folder => ({
152
+ id: folder._id,
153
+ name: folder.name,
154
+ description: folder.description,
155
+ parentId: folder.parentId,
156
+ requestCount: structure.requests.filter(r => r.parentId === folder._id).length,
157
+ })),
158
+ requests: structure.requests.map(request => ({
159
+ id: request._id,
160
+ name: request.name,
161
+ method: request.method,
162
+ url: request.url,
163
+ parentId: request.parentId,
164
+ parentName: request.parentId === collectionId
165
+ ? 'Root'
166
+ : structure.folders.find(f => f._id === request.parentId)?.name ?? 'Unknown',
167
+ hasAuth: !!request.authentication,
168
+ authType: request.authentication?.type,
169
+ })),
170
+ environments: structure.environments.map(env => ({
171
+ id: env._id,
172
+ name: env.name,
173
+ variableCount: Object.keys(env.data || {}).length,
174
+ })),
175
+ },
176
+ statistics: {
177
+ totalRequests: structure.requests.length,
178
+ totalFolders: structure.folders.length,
179
+ totalEnvironments: structure.environments.length,
180
+ methodBreakdown: structure.requests.reduce((acc, req) => {
181
+ acc[req.method] = (acc[req.method] || 0) + 1;
182
+ return acc;
183
+ }, {}),
184
+ authenticationBreakdown: structure.requests.reduce((acc, req) => {
185
+ const authType = req.authentication?.type ?? 'none';
186
+ acc[authType] = (acc[authType] || 0) + 1;
187
+ return acc;
188
+ }, {}),
189
+ },
190
+ };
191
+ return {
192
+ contents: [
193
+ {
194
+ type: 'text',
195
+ text: JSON.stringify(result, null, 2),
196
+ },
197
+ ],
198
+ };
199
+ },
200
+ },
201
+ {
202
+ uri: 'insomnia://request/{id}',
203
+ name: 'Request Detail',
204
+ description: 'Full details of a specific request',
205
+ mimeType: 'application/json',
206
+ handler: async (request) => {
207
+ const uri = request.params.uri;
208
+ const requestId = uri.replace('insomnia://request/', '');
209
+ let targetRequest = null;
210
+ let collectionInfo = null;
211
+ const collections = storage.getAllCollections();
212
+ for (const [collectionId, structure] of collections.entries()) {
213
+ const foundRequest = structure.requests.find(r => r._id === requestId);
214
+ if (foundRequest) {
215
+ targetRequest = foundRequest;
216
+ collectionInfo = {
217
+ id: collectionId,
218
+ name: structure.workspace.name,
219
+ parentName: foundRequest.parentId === collectionId
220
+ ? 'Root'
221
+ : structure.folders.find(f => f._id === foundRequest.parentId)?.name ?? 'Unknown',
222
+ };
223
+ break;
224
+ }
225
+ }
226
+ if (!targetRequest) {
227
+ throw new Error(`Request with ID ${requestId} not found`);
228
+ }
229
+ const result = {
230
+ id: targetRequest._id,
231
+ name: targetRequest.name,
232
+ description: targetRequest.description,
233
+ method: targetRequest.method,
234
+ url: targetRequest.url,
235
+ collection: collectionInfo,
236
+ headers: targetRequest.headers || [],
237
+ parameters: targetRequest.parameters || [],
238
+ body: targetRequest.body || null,
239
+ authentication: targetRequest.authentication ? {
240
+ type: targetRequest.authentication.type,
241
+ hasCredentials: !!(targetRequest.authentication.username ?? targetRequest.authentication.token),
242
+ } : null,
243
+ metadata: {
244
+ created: new Date(targetRequest.created).toISOString(),
245
+ modified: new Date(targetRequest.modified).toISOString(),
246
+ hasHeaders: (targetRequest.headers || []).length > 0,
247
+ hasParameters: (targetRequest.parameters || []).length > 0,
248
+ hasBody: !!targetRequest.body,
249
+ hasAuthentication: !!targetRequest.authentication,
250
+ },
251
+ };
252
+ return {
253
+ contents: [
254
+ {
255
+ type: 'text',
256
+ text: JSON.stringify(result, null, 2),
257
+ },
258
+ ],
259
+ };
260
+ },
261
+ },
262
+ {
263
+ uri: 'insomnia://request/{id}/history',
264
+ name: 'Request Execution History',
265
+ description: 'Get the execution history of a specific request',
266
+ mimeType: 'application/json',
267
+ handler: async (request) => {
268
+ const uri = request.params.uri;
269
+ const requestId = uri.replace('insomnia://request/', '').replace('/history', '');
270
+ let targetRequest = null;
271
+ const collections = storage.getAllCollections();
272
+ for (const structure of collections.values()) {
273
+ const foundRequest = structure.requests.find(r => r._id === requestId);
274
+ if (foundRequest) {
275
+ targetRequest = foundRequest;
276
+ break;
277
+ }
278
+ }
279
+ if (!targetRequest) {
280
+ throw new Error(`Request with ID ${requestId} not found`);
281
+ }
282
+ const history = (targetRequest.history || []).map(h => ({
283
+ id: h._id,
284
+ timestamp: new Date(h.timestamp).toISOString(),
285
+ response: {
286
+ statusCode: h.response.statusCode,
287
+ statusMessage: h.response.statusMessage,
288
+ duration: h.response.duration,
289
+ size: h.response.size,
290
+ headers: h.response.headers,
291
+ body: h.response.body,
292
+ },
293
+ error: h.error,
294
+ }));
295
+ return {
296
+ contents: [
297
+ {
298
+ type: 'text',
299
+ text: JSON.stringify(history, null, 2),
300
+ },
301
+ ],
302
+ };
303
+ },
304
+ },
305
+ {
306
+ uri: 'insomnia://search',
307
+ name: 'Search',
308
+ description: 'Search for a keyword across all collections, folders, and requests. Use with ?q=keyword',
309
+ mimeType: 'application/json',
310
+ handler: async (request) => {
311
+ const uri = request.params.uri;
312
+ const url = new URL(uri);
313
+ const keyword = url.searchParams.get('q');
314
+ if (!keyword) {
315
+ throw new Error('Search keyword must be provided with ?q=');
316
+ }
317
+ const searchResults = [];
318
+ const collections = storage.getAllCollections();
319
+ const lowerCaseKeyword = keyword.toLowerCase();
320
+ for (const [collectionId, structure] of collections.entries()) {
321
+ // Search in workspace
322
+ if (structure.workspace.name.toLowerCase().includes(lowerCaseKeyword) ||
323
+ (structure.workspace.description || '').toLowerCase().includes(lowerCaseKeyword)) {
324
+ searchResults.push({
325
+ type: 'Collection',
326
+ id: collectionId,
327
+ name: structure.workspace.name,
328
+ match: 'Name or description',
329
+ });
330
+ }
331
+ // Search in folders
332
+ for (const folder of structure.folders) {
333
+ if (folder.name.toLowerCase().includes(lowerCaseKeyword) ||
334
+ (folder.description || '').toLowerCase().includes(lowerCaseKeyword)) {
335
+ searchResults.push({
336
+ type: 'Folder',
337
+ id: folder._id,
338
+ name: folder.name,
339
+ collection: { id: collectionId, name: structure.workspace.name },
340
+ match: 'Name or description',
341
+ });
342
+ }
343
+ }
344
+ // Search in requests
345
+ for (const req of structure.requests) {
346
+ let matchReason = '';
347
+ if (req.name.toLowerCase().includes(lowerCaseKeyword))
348
+ matchReason = 'Name';
349
+ else if ((req.description || '').toLowerCase().includes(lowerCaseKeyword))
350
+ matchReason = 'Description';
351
+ else if (req.url.toLowerCase().includes(lowerCaseKeyword))
352
+ matchReason = 'URL';
353
+ else if (req.method.toLowerCase().includes(lowerCaseKeyword))
354
+ matchReason = 'Method';
355
+ if (matchReason) {
356
+ searchResults.push({
357
+ type: 'Request',
358
+ id: req._id,
359
+ name: req.name,
360
+ collection: { id: collectionId, name: structure.workspace.name },
361
+ match: matchReason,
362
+ });
363
+ }
364
+ }
365
+ }
366
+ return {
367
+ contents: [
368
+ {
369
+ type: 'text',
370
+ text: JSON.stringify(searchResults, null, 2),
371
+ },
372
+ ],
373
+ };
374
+ },
375
+ },
376
+ {
377
+ uri: 'insomnia://stats',
378
+ name: 'Statistics',
379
+ description: 'Global statistics of all collections',
380
+ mimeType: 'application/json',
381
+ handler: async () => {
382
+ const collections = storage.getAllCollections();
383
+ const totalCollections = collections.size;
384
+ let totalRequests = 0;
385
+ let totalFolders = 0;
386
+ let totalEnvironments = 0;
387
+ let totalEnvironmentVariables = 0;
388
+ const methodStats = {};
389
+ const authStats = {};
390
+ const recentActivity = [];
391
+ for (const [collectionId, structure] of collections.entries()) {
392
+ totalRequests += structure.requests.length;
393
+ totalFolders += structure.folders.length;
394
+ totalEnvironments += structure.environments.length;
395
+ structure.environments.forEach(env => {
396
+ totalEnvironmentVariables += Object.keys(env.data || {}).length;
397
+ });
398
+ structure.requests.forEach(request => {
399
+ methodStats[request.method] = (methodStats[request.method] || 0) + 1;
400
+ const authType = request.authentication?.type ?? 'none';
401
+ authStats[authType] = (authStats[authType] || 0) + 1;
402
+ recentActivity.push({
403
+ type: 'request',
404
+ id: request._id,
405
+ name: request.name,
406
+ collectionName: structure.workspace.name,
407
+ method: request.method,
408
+ modified: request.modified,
409
+ });
410
+ });
411
+ recentActivity.push({
412
+ type: 'collection',
413
+ id: collectionId,
414
+ name: structure.workspace.name,
415
+ requestCount: structure.requests.length,
416
+ modified: structure.workspace.modified,
417
+ });
418
+ }
419
+ recentActivity.sort((a, b) => b.modified - a.modified);
420
+ const result = {
421
+ summary: {
422
+ totalCollections,
423
+ totalRequests,
424
+ totalFolders,
425
+ totalEnvironments,
426
+ totalEnvironmentVariables,
427
+ },
428
+ methodBreakdown: methodStats,
429
+ authenticationBreakdown: authStats,
430
+ recentActivity: recentActivity.slice(0, 20),
431
+ averages: {
432
+ requestsPerCollection: totalCollections > 0 ? Math.round(totalRequests / totalCollections * 100) / 100 : 0,
433
+ foldersPerCollection: totalCollections > 0 ? Math.round(totalFolders / totalCollections * 100) / 100 : 0,
434
+ environmentsPerCollection: totalCollections > 0 ? Math.round(totalEnvironments / totalCollections * 100) / 100 : 0,
435
+ },
436
+ };
437
+ return {
438
+ contents: [
439
+ {
440
+ type: 'text',
441
+ text: JSON.stringify(result, null, 2),
442
+ },
443
+ ],
444
+ };
445
+ },
446
+ },
447
+ ];
448
+ }
449
+ //# sourceMappingURL=resources.js.map