har-mcp 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 +261 -0
- package/package.json +38 -0
- package/src/index.ts +33 -0
- package/src/server.ts +28 -0
- package/src/tools/export-curl.ts +134 -0
- package/src/tools/index.ts +17 -0
- package/src/tools/read-har/filters.ts +109 -0
- package/src/tools/read-har/formatters/content.ts +90 -0
- package/src/tools/read-har/formatters/cookies.ts +164 -0
- package/src/tools/read-har/formatters/detail.ts +148 -0
- package/src/tools/read-har/formatters/index.ts +12 -0
- package/src/tools/read-har/formatters/list.ts +89 -0
- package/src/tools/read-har/formatters/size.ts +150 -0
- package/src/tools/read-har/formatters/stats.ts +129 -0
- package/src/tools/read-har/formatters/summary.ts +174 -0
- package/src/tools/read-har/formatters/timeline.ts +95 -0
- package/src/tools/read-har/helpers.ts +237 -0
- package/src/tools/read-har/index.ts +393 -0
- package/src/tools/read-har/repair.ts +277 -0
- package/src/tools/read-har/schema.ts +82 -0
- package/src/tools/read-har.ts +15 -0
- package/src/types/har-to-curl.d.ts +11 -0
- package/src/types/har.ts +386 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema Definition for Read HAR Tool
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { z } from "zod"
|
|
6
|
+
|
|
7
|
+
export const readHarSchema = z.object({
|
|
8
|
+
path: z.string().describe("Path to the HAR file"),
|
|
9
|
+
|
|
10
|
+
mode: z
|
|
11
|
+
.enum(["summary", "list", "detail", "content", "stats", "timeline", "size", "cookies"])
|
|
12
|
+
.default("summary")
|
|
13
|
+
.describe(
|
|
14
|
+
"Output mode: summary (overview), list (entries), detail (full metadata), content (with body), stats (aggregate by endpoint), timeline (waterfall visualization), size (payload size analysis), cookies (cookie propagation tracking)",
|
|
15
|
+
),
|
|
16
|
+
|
|
17
|
+
// Pagination
|
|
18
|
+
page: z.number().int().min(1).default(1),
|
|
19
|
+
pageSize: z.number().int().min(1).max(100).default(20),
|
|
20
|
+
|
|
21
|
+
// Entry selection (required for content mode)
|
|
22
|
+
entries: z
|
|
23
|
+
.array(z.number().int().min(0))
|
|
24
|
+
.max(10)
|
|
25
|
+
.optional()
|
|
26
|
+
.describe("Specific entry indexes to return (required for content mode)"),
|
|
27
|
+
|
|
28
|
+
// Filtering
|
|
29
|
+
filter: z
|
|
30
|
+
.object({
|
|
31
|
+
url: z.string().optional().describe("URL pattern (substring, glob with *, or ~regex)"),
|
|
32
|
+
method: z.union([z.string(), z.array(z.string())]).optional(),
|
|
33
|
+
status: z
|
|
34
|
+
.union([
|
|
35
|
+
z.number(),
|
|
36
|
+
z.string().regex(/^\d{1}xx$/i),
|
|
37
|
+
z.object({ min: z.number().optional(), max: z.number().optional() }),
|
|
38
|
+
])
|
|
39
|
+
.optional(),
|
|
40
|
+
contentType: z.string().optional(),
|
|
41
|
+
minDuration: z.number().optional(),
|
|
42
|
+
hasError: z.boolean().optional(),
|
|
43
|
+
bodyContains: z.string().optional().describe("Filter entries whose response body contains this string"),
|
|
44
|
+
})
|
|
45
|
+
.optional(),
|
|
46
|
+
|
|
47
|
+
// Include options for detail mode
|
|
48
|
+
include: z
|
|
49
|
+
.object({
|
|
50
|
+
headers: z.boolean().optional().default(false),
|
|
51
|
+
cookies: z.boolean().optional().default(false),
|
|
52
|
+
timing: z.boolean().optional().default(true),
|
|
53
|
+
queryParams: z.boolean().optional().default(true),
|
|
54
|
+
})
|
|
55
|
+
.optional(),
|
|
56
|
+
|
|
57
|
+
// Content options
|
|
58
|
+
contentOptions: z
|
|
59
|
+
.object({
|
|
60
|
+
includeRequestBody: z.boolean().optional().default(false),
|
|
61
|
+
includeResponseBody: z.boolean().optional().default(true),
|
|
62
|
+
maxContentLength: z.number().optional().default(50000),
|
|
63
|
+
})
|
|
64
|
+
.optional(),
|
|
65
|
+
|
|
66
|
+
// Sorting
|
|
67
|
+
sort: z
|
|
68
|
+
.object({
|
|
69
|
+
by: z.enum(["index", "time", "duration", "size", "status"]).default("index"),
|
|
70
|
+
order: z.enum(["asc", "desc"]).default("asc"),
|
|
71
|
+
})
|
|
72
|
+
.optional(),
|
|
73
|
+
|
|
74
|
+
// Output format
|
|
75
|
+
format: z
|
|
76
|
+
.enum(["markdown", "json"])
|
|
77
|
+
.default("markdown")
|
|
78
|
+
.describe("Output format: markdown (default) or json for programmatic use"),
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
export type ReadHarInput = z.infer<typeof readHarSchema>
|
|
82
|
+
export type ReadHarInputRaw = z.input<typeof readHarSchema>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read HAR Tool - Re-export for backward compatibility
|
|
3
|
+
*
|
|
4
|
+
* This file re-exports everything from the read-har module for backward compatibility.
|
|
5
|
+
* The actual implementation has been split into smaller, more maintainable sub-modules.
|
|
6
|
+
*
|
|
7
|
+
* @see ./read-har/index.ts for the main implementation
|
|
8
|
+
* @see ./read-har/schema.ts for schema definitions
|
|
9
|
+
* @see ./read-har/helpers.ts for helper functions
|
|
10
|
+
* @see ./read-har/filters.ts for filter and sort functions
|
|
11
|
+
* @see ./read-har/formatters/ for output formatters
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
// Re-export everything for backward compatibility
|
|
15
|
+
export * from "./read-har/index.ts"
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
declare module "har-to-curl" {
|
|
2
|
+
/**
|
|
3
|
+
* Converts a HAR entry to a cURL command string
|
|
4
|
+
* @param entry - A HAR entry object following HAR 1.2 specification
|
|
5
|
+
* @returns The cURL command as a string
|
|
6
|
+
*/
|
|
7
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
8
|
+
function harToCurl(entry: any): string
|
|
9
|
+
|
|
10
|
+
export default harToCurl
|
|
11
|
+
}
|
package/src/types/har.ts
ADDED
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import { z } from "zod"
|
|
2
|
+
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// HAR 1.2 Type Definitions
|
|
5
|
+
// Based on W3C HAR 1.2 Specification
|
|
6
|
+
// ============================================================================
|
|
7
|
+
|
|
8
|
+
// --- Name/Value Types ---
|
|
9
|
+
|
|
10
|
+
export interface HarHeader {
|
|
11
|
+
name: string
|
|
12
|
+
value: string
|
|
13
|
+
comment?: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface HarQueryParam {
|
|
17
|
+
name: string
|
|
18
|
+
value: string
|
|
19
|
+
comment?: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface HarPostParam {
|
|
23
|
+
name: string
|
|
24
|
+
value?: string
|
|
25
|
+
fileName?: string
|
|
26
|
+
contentType?: string
|
|
27
|
+
comment?: string
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface HarCookie {
|
|
31
|
+
name: string
|
|
32
|
+
value: string
|
|
33
|
+
path?: string
|
|
34
|
+
domain?: string
|
|
35
|
+
expires?: string
|
|
36
|
+
httpOnly?: boolean
|
|
37
|
+
secure?: boolean
|
|
38
|
+
comment?: string
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// --- Creator/Browser ---
|
|
42
|
+
|
|
43
|
+
export interface HarCreator {
|
|
44
|
+
name: string
|
|
45
|
+
version: string
|
|
46
|
+
comment?: string
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface HarBrowser {
|
|
50
|
+
name: string
|
|
51
|
+
version: string
|
|
52
|
+
comment?: string
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// --- Page Timings ---
|
|
56
|
+
|
|
57
|
+
export interface HarPageTimings {
|
|
58
|
+
onContentLoad?: number
|
|
59
|
+
onLoad?: number
|
|
60
|
+
comment?: string
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface HarPage {
|
|
64
|
+
startedDateTime: string
|
|
65
|
+
id: string
|
|
66
|
+
title: string
|
|
67
|
+
pageTimings: HarPageTimings
|
|
68
|
+
comment?: string
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// --- Timings ---
|
|
72
|
+
|
|
73
|
+
export interface HarTimings {
|
|
74
|
+
blocked?: number
|
|
75
|
+
dns?: number
|
|
76
|
+
connect?: number
|
|
77
|
+
send: number
|
|
78
|
+
wait: number
|
|
79
|
+
receive: number
|
|
80
|
+
ssl?: number
|
|
81
|
+
comment?: string
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// --- Cache ---
|
|
85
|
+
|
|
86
|
+
export interface HarCacheEntry {
|
|
87
|
+
expires?: string
|
|
88
|
+
lastAccess: string
|
|
89
|
+
eTag: string
|
|
90
|
+
hitCount: number
|
|
91
|
+
comment?: string
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface HarCache {
|
|
95
|
+
beforeRequest?: HarCacheEntry | null
|
|
96
|
+
afterRequest?: HarCacheEntry | null
|
|
97
|
+
comment?: string
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// --- Content ---
|
|
101
|
+
|
|
102
|
+
export interface HarContent {
|
|
103
|
+
size: number
|
|
104
|
+
compression?: number
|
|
105
|
+
mimeType: string
|
|
106
|
+
text?: string
|
|
107
|
+
encoding?: string
|
|
108
|
+
comment?: string
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export interface HarPostData {
|
|
112
|
+
mimeType: string
|
|
113
|
+
params?: HarPostParam[]
|
|
114
|
+
text?: string
|
|
115
|
+
comment?: string
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// --- Request/Response ---
|
|
119
|
+
|
|
120
|
+
export interface HarRequest {
|
|
121
|
+
method: string
|
|
122
|
+
url: string
|
|
123
|
+
httpVersion: string
|
|
124
|
+
cookies: HarCookie[]
|
|
125
|
+
headers: HarHeader[]
|
|
126
|
+
queryString: HarQueryParam[]
|
|
127
|
+
postData?: HarPostData
|
|
128
|
+
headersSize: number
|
|
129
|
+
bodySize: number
|
|
130
|
+
comment?: string
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export interface HarResponse {
|
|
134
|
+
status: number
|
|
135
|
+
statusText: string
|
|
136
|
+
httpVersion: string
|
|
137
|
+
cookies: HarCookie[]
|
|
138
|
+
headers: HarHeader[]
|
|
139
|
+
content: HarContent
|
|
140
|
+
redirectURL: string
|
|
141
|
+
headersSize: number
|
|
142
|
+
bodySize: number
|
|
143
|
+
comment?: string
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// --- Entry ---
|
|
147
|
+
|
|
148
|
+
export interface HarEntry {
|
|
149
|
+
pageref?: string
|
|
150
|
+
startedDateTime: string
|
|
151
|
+
time: number
|
|
152
|
+
request: HarRequest
|
|
153
|
+
response: HarResponse
|
|
154
|
+
cache: HarCache
|
|
155
|
+
timings: HarTimings
|
|
156
|
+
serverIPAddress?: string
|
|
157
|
+
connection?: string
|
|
158
|
+
comment?: string
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// --- Log ---
|
|
162
|
+
|
|
163
|
+
export interface HarLog {
|
|
164
|
+
version: string
|
|
165
|
+
creator: HarCreator
|
|
166
|
+
browser?: HarBrowser
|
|
167
|
+
pages?: HarPage[]
|
|
168
|
+
entries: HarEntry[]
|
|
169
|
+
comment?: string
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// --- Main HAR File ---
|
|
173
|
+
|
|
174
|
+
export interface HarFile {
|
|
175
|
+
log: HarLog
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// ============================================================================
|
|
179
|
+
// Zod Schemas for Runtime Validation
|
|
180
|
+
// ============================================================================
|
|
181
|
+
|
|
182
|
+
export const HarHeaderSchema = z.object({
|
|
183
|
+
name: z.string(),
|
|
184
|
+
value: z.string(),
|
|
185
|
+
comment: z.string().optional(),
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
export const HarQueryParamSchema = z.object({
|
|
189
|
+
name: z.string(),
|
|
190
|
+
value: z.string(),
|
|
191
|
+
comment: z.string().optional(),
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
export const HarPostParamSchema = z.object({
|
|
195
|
+
name: z.string(),
|
|
196
|
+
value: z.string().optional(),
|
|
197
|
+
fileName: z.string().optional(),
|
|
198
|
+
contentType: z.string().optional(),
|
|
199
|
+
comment: z.string().optional(),
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
export const HarCookieSchema = z.object({
|
|
203
|
+
name: z.string(),
|
|
204
|
+
value: z.string(),
|
|
205
|
+
path: z.string().optional(),
|
|
206
|
+
domain: z.string().optional(),
|
|
207
|
+
expires: z.string().optional(),
|
|
208
|
+
httpOnly: z.boolean().optional(),
|
|
209
|
+
secure: z.boolean().optional(),
|
|
210
|
+
comment: z.string().optional(),
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
export const HarCreatorSchema = z.object({
|
|
214
|
+
name: z.string(),
|
|
215
|
+
version: z.string(),
|
|
216
|
+
comment: z.string().optional(),
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
export const HarBrowserSchema = z.object({
|
|
220
|
+
name: z.string(),
|
|
221
|
+
version: z.string(),
|
|
222
|
+
comment: z.string().optional(),
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
export const HarPageTimingsSchema = z.object({
|
|
226
|
+
onContentLoad: z.number().optional(),
|
|
227
|
+
onLoad: z.number().optional(),
|
|
228
|
+
comment: z.string().optional(),
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
export const HarPageSchema = z.object({
|
|
232
|
+
startedDateTime: z.string(),
|
|
233
|
+
id: z.string(),
|
|
234
|
+
title: z.string(),
|
|
235
|
+
pageTimings: HarPageTimingsSchema,
|
|
236
|
+
comment: z.string().optional(),
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
// Use .passthrough() to allow Chrome DevTools extensions (fields starting with _)
|
|
240
|
+
export const HarTimingsSchema = z
|
|
241
|
+
.object({
|
|
242
|
+
blocked: z.number().optional(),
|
|
243
|
+
dns: z.number().optional(),
|
|
244
|
+
connect: z.number().optional(),
|
|
245
|
+
send: z.number(),
|
|
246
|
+
wait: z.number(),
|
|
247
|
+
receive: z.number(),
|
|
248
|
+
ssl: z.number().optional(),
|
|
249
|
+
comment: z.string().optional(),
|
|
250
|
+
})
|
|
251
|
+
.passthrough()
|
|
252
|
+
|
|
253
|
+
export const HarCacheEntrySchema = z.object({
|
|
254
|
+
expires: z.string().optional(),
|
|
255
|
+
lastAccess: z.string(),
|
|
256
|
+
eTag: z.string(),
|
|
257
|
+
hitCount: z.number(),
|
|
258
|
+
comment: z.string().optional(),
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
// Chrome often exports empty cache objects - make this fully optional and passthrough
|
|
262
|
+
export const HarCacheSchema = z
|
|
263
|
+
.object({
|
|
264
|
+
beforeRequest: HarCacheEntrySchema.nullable().optional(),
|
|
265
|
+
afterRequest: HarCacheEntrySchema.nullable().optional(),
|
|
266
|
+
comment: z.string().optional(),
|
|
267
|
+
})
|
|
268
|
+
.passthrough()
|
|
269
|
+
|
|
270
|
+
// Chrome DevTools extensions: passthrough allows _transferSize, _error, _fetchedViaServiceWorker, etc.
|
|
271
|
+
export const HarContentSchema = z
|
|
272
|
+
.object({
|
|
273
|
+
size: z.number(),
|
|
274
|
+
compression: z.number().optional(),
|
|
275
|
+
mimeType: z.string(),
|
|
276
|
+
text: z.string().optional(),
|
|
277
|
+
encoding: z.string().optional(),
|
|
278
|
+
comment: z.string().optional(),
|
|
279
|
+
})
|
|
280
|
+
.passthrough()
|
|
281
|
+
|
|
282
|
+
export const HarPostDataSchema = z
|
|
283
|
+
.object({
|
|
284
|
+
mimeType: z.string(),
|
|
285
|
+
params: z.array(HarPostParamSchema).optional(),
|
|
286
|
+
text: z.string().optional(),
|
|
287
|
+
comment: z.string().optional(),
|
|
288
|
+
})
|
|
289
|
+
.passthrough()
|
|
290
|
+
|
|
291
|
+
export const HarRequestSchema = z
|
|
292
|
+
.object({
|
|
293
|
+
method: z.string(),
|
|
294
|
+
url: z.string(),
|
|
295
|
+
httpVersion: z.string(),
|
|
296
|
+
cookies: z.array(HarCookieSchema),
|
|
297
|
+
headers: z.array(HarHeaderSchema),
|
|
298
|
+
queryString: z.array(HarQueryParamSchema),
|
|
299
|
+
postData: HarPostDataSchema.optional(),
|
|
300
|
+
headersSize: z.number(),
|
|
301
|
+
bodySize: z.number(),
|
|
302
|
+
comment: z.string().optional(),
|
|
303
|
+
})
|
|
304
|
+
.passthrough()
|
|
305
|
+
|
|
306
|
+
// Chrome DevTools extensions: _transferSize, _error, _fetchedViaServiceWorker, etc.
|
|
307
|
+
export const HarResponseSchema = z
|
|
308
|
+
.object({
|
|
309
|
+
status: z.number(),
|
|
310
|
+
statusText: z.string(),
|
|
311
|
+
httpVersion: z.string(),
|
|
312
|
+
cookies: z.array(HarCookieSchema),
|
|
313
|
+
headers: z.array(HarHeaderSchema),
|
|
314
|
+
content: HarContentSchema,
|
|
315
|
+
redirectURL: z.string(),
|
|
316
|
+
headersSize: z.number(),
|
|
317
|
+
bodySize: z.number(),
|
|
318
|
+
comment: z.string().optional(),
|
|
319
|
+
})
|
|
320
|
+
.passthrough()
|
|
321
|
+
|
|
322
|
+
// Chrome DevTools extensions: _connectionId, _initiator, _priority, _resourceType, etc.
|
|
323
|
+
export const HarEntrySchema = z
|
|
324
|
+
.object({
|
|
325
|
+
pageref: z.string().optional(),
|
|
326
|
+
startedDateTime: z.string(),
|
|
327
|
+
time: z.number(),
|
|
328
|
+
request: HarRequestSchema,
|
|
329
|
+
response: HarResponseSchema,
|
|
330
|
+
cache: HarCacheSchema,
|
|
331
|
+
timings: HarTimingsSchema,
|
|
332
|
+
serverIPAddress: z.string().optional(),
|
|
333
|
+
connection: z.string().optional(),
|
|
334
|
+
comment: z.string().optional(),
|
|
335
|
+
})
|
|
336
|
+
.passthrough()
|
|
337
|
+
|
|
338
|
+
export const HarLogSchema = z
|
|
339
|
+
.object({
|
|
340
|
+
version: z.string(),
|
|
341
|
+
creator: HarCreatorSchema,
|
|
342
|
+
browser: HarBrowserSchema.optional(),
|
|
343
|
+
pages: z.array(HarPageSchema).optional(),
|
|
344
|
+
entries: z.array(HarEntrySchema),
|
|
345
|
+
comment: z.string().optional(),
|
|
346
|
+
})
|
|
347
|
+
.passthrough()
|
|
348
|
+
|
|
349
|
+
export const HarFileSchema = z
|
|
350
|
+
.object({
|
|
351
|
+
log: HarLogSchema,
|
|
352
|
+
})
|
|
353
|
+
.passthrough()
|
|
354
|
+
|
|
355
|
+
// ============================================================================
|
|
356
|
+
// Type Inference from Zod Schemas (alternative types)
|
|
357
|
+
// ============================================================================
|
|
358
|
+
|
|
359
|
+
export type HarFileFromSchema = z.infer<typeof HarFileSchema>
|
|
360
|
+
export type HarLogFromSchema = z.infer<typeof HarLogSchema>
|
|
361
|
+
export type HarEntryFromSchema = z.infer<typeof HarEntrySchema>
|
|
362
|
+
export type HarRequestFromSchema = z.infer<typeof HarRequestSchema>
|
|
363
|
+
export type HarResponseFromSchema = z.infer<typeof HarResponseSchema>
|
|
364
|
+
|
|
365
|
+
// ============================================================================
|
|
366
|
+
// Validation Helper Functions
|
|
367
|
+
// ============================================================================
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Validates a HAR file object against the HAR 1.2 specification
|
|
371
|
+
* @param data - The data to validate
|
|
372
|
+
* @returns The validated HarFile object
|
|
373
|
+
* @throws ZodError if validation fails
|
|
374
|
+
*/
|
|
375
|
+
export function validateHarFile(data: unknown): HarFile {
|
|
376
|
+
return HarFileSchema.parse(data)
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Safely validates a HAR file object, returning a result object
|
|
381
|
+
* @param data - The data to validate
|
|
382
|
+
* @returns A Zod SafeParseReturnType with success status and data/error
|
|
383
|
+
*/
|
|
384
|
+
export function safeValidateHarFile(data: unknown) {
|
|
385
|
+
return HarFileSchema.safeParse(data)
|
|
386
|
+
}
|