@impart-security/impart-mcp 0.1.0 → 0.1.1

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
@@ -82,6 +82,7 @@ To use Impart MCP with Claude Desktop, you'll need to configure the MCP server i
82
82
  "impart": {
83
83
  "command": "npx",
84
84
  "args": [
85
+ "-y",
85
86
  "@impart-security/impart-mcp"
86
87
  ],
87
88
  "env": {
@@ -117,7 +118,10 @@ Add the Impart MCP server configuration:
117
118
  "mcpServers": {
118
119
  "impart": {
119
120
  "command": "npx",
120
- "args": ["@impart-security/impart-mcp"],
121
+ "args": [
122
+ "-y",
123
+ "@impart-security/impart-mcp"
124
+ ],
121
125
  "env": {
122
126
  "IMPART_AUTH_TOKEN": "your_auth_token"
123
127
  }
@@ -140,4 +144,3 @@ ISC
140
144
 
141
145
  For support, please contact Impart support or open an issue on GitHub.
142
146
 
143
-
@@ -0,0 +1,4 @@
1
+ import type { AxiosInstance, AxiosRequestConfig } from "axios";
2
+ export declare const createClient: () => AxiosInstance;
3
+ export declare const client: AxiosInstance;
4
+ export declare function makeRequest<T>(config: AxiosRequestConfig): Promise<T>;
package/dist/client.js ADDED
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.client = exports.createClient = void 0;
7
+ exports.makeRequest = makeRequest;
8
+ const axios_1 = __importDefault(require("axios"));
9
+ const config_js_1 = require("./config.js");
10
+ // Create axios instance with default configuration
11
+ const createClient = () => {
12
+ const client = axios_1.default.create({
13
+ baseURL: config_js_1.config.apiBase,
14
+ headers: {
15
+ Authorization: `Bearer ${config_js_1.config.authToken}`,
16
+ "User-Agent": config_js_1.config.userAgent,
17
+ "X-Impart-Org-ID": config_js_1.config.orgId,
18
+ "Content-Type": "application/json",
19
+ },
20
+ });
21
+ // Add request interceptor for error handling
22
+ client.interceptors.response.use((response) => response, (error) => {
23
+ if (error.response) {
24
+ const { status, data } = error.response;
25
+ throw new Error(`API request failed with status ${status}: ${JSON.stringify(data)}`);
26
+ }
27
+ throw error;
28
+ });
29
+ return client;
30
+ };
31
+ exports.createClient = createClient;
32
+ // Export default client instance
33
+ exports.client = (0, exports.createClient)();
34
+ // Helper function to make API requests with proper typing
35
+ async function makeRequest(config) {
36
+ const response = await exports.client.request(config);
37
+ return response.data;
38
+ }
@@ -0,0 +1,6 @@
1
+ export declare const config: {
2
+ readonly apiBase: string;
3
+ readonly authToken: string;
4
+ readonly orgId: string;
5
+ readonly userAgent: "impart-mcp/1.0.0";
6
+ };
package/dist/config.js ADDED
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.config = void 0;
4
+ const getOrgId_js_1 = require("./getOrgId.js");
5
+ const { env } = process;
6
+ if (!env["IMPART_AUTH_TOKEN"]) {
7
+ throw new Error("IMPART_AUTH_TOKEN environment variable is required");
8
+ }
9
+ // Export configuration
10
+ exports.config = {
11
+ apiBase: env["IMPART_API_BASE"] ?? "https://api.impartsecurity.net/v0",
12
+ authToken: env["IMPART_AUTH_TOKEN"],
13
+ orgId: (0, getOrgId_js_1.getOrgId)(env["IMPART_AUTH_TOKEN"]),
14
+ userAgent: "impart-mcp/1.0.0",
15
+ };
@@ -0,0 +1 @@
1
+ export declare function getOrgId(accessToken: string): string;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getOrgId = getOrgId;
4
+ function getOrgId(accessToken) {
5
+ let sub = "";
6
+ try {
7
+ const tokenData = accessToken.split(".")[1];
8
+ const decodedTokenRaw = atob(tokenData ?? "");
9
+ const decodedToken = JSON.parse(decodedTokenRaw);
10
+ if (decodedToken.sub) {
11
+ sub = decodedToken.sub;
12
+ }
13
+ }
14
+ catch {
15
+ throw new Error("Failed to parse access token");
16
+ }
17
+ if (!sub.startsWith("org:")) {
18
+ throw new Error("Access token is not for an organization");
19
+ }
20
+ return sub.substring(4);
21
+ }
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,1090 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
4
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
5
+ const zod_1 = require("zod");
6
+ const config_js_1 = require("./config.js");
7
+ // Create server instance
8
+ const server = new mcp_js_1.McpServer({
9
+ name: "impart-mcp",
10
+ version: "1.0.0",
11
+ capabilities: {
12
+ resources: {},
13
+ tools: {},
14
+ },
15
+ });
16
+ // Helper function to validate page parameter
17
+ function validatePage(page) {
18
+ return Math.max(1, page); // Ensure page is at least 1
19
+ }
20
+ // Helper function for making Impart API requests
21
+ async function makeImpartRequest(endpoint, queryParams, method = "GET", body) {
22
+ const headers = {
23
+ "User-Agent": config_js_1.config.userAgent,
24
+ Accept: "application/security.impart.api.v0+json",
25
+ Authorization: `Bearer ${config_js_1.config.authToken}`,
26
+ };
27
+ if (body) {
28
+ headers["Content-Type"] = "application/json";
29
+ }
30
+ const url = new URL(`${config_js_1.config.apiBase}/orgs/${config_js_1.config.orgId}/${endpoint}`);
31
+ if (queryParams) {
32
+ Object.entries(queryParams).forEach(([key, value]) => {
33
+ if (value !== null && value !== undefined) {
34
+ if (Array.isArray(value)) {
35
+ value.forEach((v) => url.searchParams.append(key, v.toString()));
36
+ }
37
+ else {
38
+ url.searchParams.append(key, value.toString());
39
+ }
40
+ }
41
+ });
42
+ }
43
+ try {
44
+ const response = await fetch(url.toString(), {
45
+ method,
46
+ headers,
47
+ body: body ? JSON.stringify(body) : "",
48
+ });
49
+ if (!response.ok) {
50
+ throw new Error(`HTTP error! status: ${response.status}`);
51
+ }
52
+ return (await response.json());
53
+ }
54
+ catch (error) {
55
+ console.error("Error making Impart request:", error);
56
+ return null;
57
+ }
58
+ }
59
+ // Register tools with consistent naming patterns
60
+ server.tool("list_inspectors", "Get a list of inspectors for the organization", {
61
+ page: zod_1.z
62
+ .number()
63
+ .default(1)
64
+ .describe("The page of results to return (minimum value: 1)"),
65
+ max_results: zod_1.z
66
+ .number()
67
+ .default(100)
68
+ .describe("The maximum number of results to return"),
69
+ }, async ({ page, max_results }) => {
70
+ const queryParams = {
71
+ page: validatePage(page),
72
+ max_results,
73
+ };
74
+ const data = await makeImpartRequest("inspectors", queryParams);
75
+ if (!data) {
76
+ return {
77
+ content: [
78
+ { type: "text", text: "Unable to fetch inspectors: Unknown error" },
79
+ ],
80
+ };
81
+ }
82
+ const inspectors = data.items || [];
83
+ if (inspectors.length === 0) {
84
+ return {
85
+ content: [
86
+ { type: "text", text: "No inspectors found for this organization." },
87
+ ],
88
+ };
89
+ }
90
+ const formattedInspectors = inspectors.map((inspector) => [
91
+ `ID: ${inspector.id}`,
92
+ `Version: ${inspector.version}`,
93
+ `Last Seen: ${inspector.last_seen}`,
94
+ "---",
95
+ ].join("\n"));
96
+ return {
97
+ content: [{ type: "text", text: formattedInspectors.join("\n") }],
98
+ };
99
+ });
100
+ // Rules Script Tools
101
+ server.tool("list_rules_scripts", "Get a list of rules scripts for your Impart organization", {
102
+ page: zod_1.z
103
+ .number()
104
+ .default(1)
105
+ .describe("The page of results to return (minimum value: 1)"),
106
+ max_results: zod_1.z
107
+ .number()
108
+ .default(100)
109
+ .describe("The maximum number of results to return"),
110
+ type: zod_1.z
111
+ .string()
112
+ .optional()
113
+ .describe("Filter by type of rule script ('custom' or 'core')"),
114
+ exclude_src: zod_1.z
115
+ .boolean()
116
+ .default(false)
117
+ .describe("Whether to exclude the rule script source"),
118
+ exclude_revisions: zod_1.z
119
+ .boolean()
120
+ .default(false)
121
+ .describe("Whether to exclude rule script revisions"),
122
+ is_disabled: zod_1.z
123
+ .string()
124
+ .optional()
125
+ .describe("Filter by disabled status ('true' or 'false')"),
126
+ label: zod_1.z.array(zod_1.z.string()).optional().describe("Filter by label slugs"),
127
+ }, async ({ page, max_results, type, exclude_src, exclude_revisions, is_disabled, label, }) => {
128
+ const queryParams = {
129
+ page: validatePage(page),
130
+ max_results,
131
+ type,
132
+ exclude_src,
133
+ exclude_revisions,
134
+ is_disabled,
135
+ label,
136
+ };
137
+ const data = await makeImpartRequest("rules_scripts", queryParams);
138
+ if (!data) {
139
+ return {
140
+ content: [
141
+ {
142
+ type: "text",
143
+ text: "Unable to fetch rules scripts: Unknown error",
144
+ },
145
+ ],
146
+ };
147
+ }
148
+ const scripts = data.items || [];
149
+ if (scripts.length === 0) {
150
+ return {
151
+ content: [
152
+ {
153
+ type: "text",
154
+ text: "No rules scripts found for this organization.",
155
+ },
156
+ ],
157
+ };
158
+ }
159
+ const formattedScripts = scripts.map((script) => [
160
+ `ID: ${script.id}`,
161
+ `Name: ${script.name}`,
162
+ `Description: ${script.description ?? "N/A"}`,
163
+ `Type: ${script.type}`,
164
+ `Disabled: ${script.disabled}`,
165
+ `Blocking Effect: ${script.blocking_effect}`,
166
+ `Language: ${script.lang}`,
167
+ `Revision: ${script.revision}`,
168
+ `Labels: ${script.labels.join(", ")}`,
169
+ `Created By: ${script.created_by}`,
170
+ `Created At: ${script.created_at}`,
171
+ `Updated By: ${script.updated_by}`,
172
+ `Updated At: ${script.updated_at}`,
173
+ "---",
174
+ ].join("\n"));
175
+ return {
176
+ content: [{ type: "text", text: formattedScripts.join("\n") }],
177
+ };
178
+ });
179
+ server.tool("get_rules_script", "Get details of a specific rules script", {
180
+ rules_script_id: zod_1.z
181
+ .string()
182
+ .describe("The unique identifier of the rules script"),
183
+ revision: zod_1.z.number().optional().describe("The specific revision to fetch"),
184
+ }, async ({ rules_script_id, revision }) => {
185
+ if (!rules_script_id) {
186
+ return {
187
+ content: [
188
+ { type: "text", text: "Error: rules_script_id is required." },
189
+ ],
190
+ };
191
+ }
192
+ const queryParams = revision ? { revision } : undefined;
193
+ const data = await makeImpartRequest(`rules_scripts/${rules_script_id}`, queryParams);
194
+ if (!data) {
195
+ return {
196
+ content: [
197
+ { type: "text", text: "Unable to fetch rules script: Unknown error" },
198
+ ],
199
+ };
200
+ }
201
+ const formattedScript = [
202
+ `ID: ${data.id}`,
203
+ `Name: ${data.name}`,
204
+ `Description: ${data.description ?? "N/A"}`,
205
+ `Type: ${data.type}`,
206
+ `Disabled: ${data.disabled}`,
207
+ `Blocking Effect: ${data.blocking_effect}`,
208
+ `Language: ${data.lang}`,
209
+ `Source Code: ${data.src ?? "N/A"}`,
210
+ `Autogenerated Explanation: ${data.autogenerated_explanation ?? "N/A"}`,
211
+ `Revision: ${data.revision}`,
212
+ `Dependencies: ${(data.dependencies ?? []).join(", ")}`,
213
+ `Labels: ${data.labels.join(", ")}`,
214
+ `Created By: ${data.created_by}`,
215
+ `Created At: ${data.created_at}`,
216
+ `Updated By: ${data.updated_by}`,
217
+ `Updated At: ${data.updated_at}`,
218
+ "---",
219
+ "Revisions:",
220
+ ];
221
+ data.revisions.forEach((revision) => {
222
+ formattedScript.push(` Revision: ${revision.revision}`, ` Created By: ${revision.created_by}`, ` Created At: ${revision.created_at}`, "---");
223
+ });
224
+ return {
225
+ content: [{ type: "text", text: formattedScript.join("\n") }],
226
+ };
227
+ });
228
+ server.tool("create_rules_script", "Creates a new rules script for the organization", {
229
+ name: zod_1.z.string().describe("The name of the rules script"),
230
+ src: zod_1.z
231
+ .string()
232
+ .describe("The base64-encoded source code of the rules script"),
233
+ lang: zod_1.z
234
+ .string()
235
+ .default("assemblyscript")
236
+ .describe("The language of the script"),
237
+ description: zod_1.z
238
+ .string()
239
+ .optional()
240
+ .describe("Optional description of the script"),
241
+ blocking_effect: zod_1.z
242
+ .string()
243
+ .default("block")
244
+ .describe("Effect when rule blocks"),
245
+ disabled: zod_1.z
246
+ .boolean()
247
+ .default(false)
248
+ .describe("Whether the script is disabled"),
249
+ labels: zod_1.z
250
+ .array(zod_1.z.string())
251
+ .optional()
252
+ .describe("Optional list of label slugs"),
253
+ }, async ({ name, src, lang, description, blocking_effect, disabled, labels, }) => {
254
+ const payload = {
255
+ name,
256
+ src,
257
+ lang,
258
+ description,
259
+ blocking_effect,
260
+ disabled,
261
+ labels: labels ?? [],
262
+ };
263
+ const data = await makeImpartRequest("rules_scripts", undefined, "POST", payload);
264
+ if (!data) {
265
+ return {
266
+ content: [{ type: "text", text: "Failed to create rules script" }],
267
+ };
268
+ }
269
+ const formattedScript = [
270
+ "Rules script created successfully:",
271
+ `ID: ${data.id}`,
272
+ `Name: ${data.name}`,
273
+ `Description: ${data.description ?? "N/A"}`,
274
+ `Language: ${data.lang}`,
275
+ `Blocking Effect: ${data.blocking_effect}`,
276
+ `Disabled: ${data.disabled}`,
277
+ `Labels: ${data.labels.join(", ")}`,
278
+ `Created At: ${data.created_at}`,
279
+ "---",
280
+ ].join("\n");
281
+ return {
282
+ content: [{ type: "text", text: formattedScript }],
283
+ };
284
+ });
285
+ server.tool("update_rules_script", "Updates an existing rules script", {
286
+ rules_script_id: zod_1.z
287
+ .string()
288
+ .describe("The ID of the rules script to update"),
289
+ name: zod_1.z.string().describe("The name of the rules script"),
290
+ src: zod_1.z.string().describe("The source code of the rules script"),
291
+ lang: zod_1.z
292
+ .string()
293
+ .default("assemblyscript")
294
+ .describe("The language of the script"),
295
+ description: zod_1.z
296
+ .string()
297
+ .optional()
298
+ .describe("Optional description of the script"),
299
+ blocking_effect: zod_1.z
300
+ .string()
301
+ .default("block")
302
+ .describe("Effect when rule blocks"),
303
+ disabled: zod_1.z
304
+ .boolean()
305
+ .default(false)
306
+ .describe("Whether the script is disabled"),
307
+ labels: zod_1.z
308
+ .array(zod_1.z.string())
309
+ .optional()
310
+ .describe("Optional list of label slugs"),
311
+ }, async ({ rules_script_id, name, src, lang, description, blocking_effect, disabled, labels, }) => {
312
+ if (!rules_script_id) {
313
+ return {
314
+ content: [
315
+ { type: "text", text: "Error: rules_script_id is required." },
316
+ ],
317
+ };
318
+ }
319
+ const payload = {
320
+ name,
321
+ src,
322
+ lang,
323
+ description,
324
+ blocking_effect,
325
+ disabled,
326
+ labels: labels ?? [],
327
+ };
328
+ const data = await makeImpartRequest(`rules_scripts/${rules_script_id}`, undefined, "PUT", payload);
329
+ if (!data) {
330
+ return {
331
+ content: [{ type: "text", text: "Failed to update rules script" }],
332
+ };
333
+ }
334
+ const formattedScript = [
335
+ "Rules script updated successfully:",
336
+ `ID: ${data.id}`,
337
+ `Name: ${data.name}`,
338
+ `Description: ${data.description ?? "N/A"}`,
339
+ `Language: ${data.lang}`,
340
+ `Blocking Effect: ${data.blocking_effect}`,
341
+ `Disabled: ${data.disabled}`,
342
+ `Labels: ${data.labels.join(", ")}`,
343
+ `Updated At: ${data.updated_at}`,
344
+ "---",
345
+ ].join("\n");
346
+ return {
347
+ content: [{ type: "text", text: formattedScript }],
348
+ };
349
+ });
350
+ server.tool("write_rule_script", "Generate a rule script using Impart's LLM", {
351
+ query: zod_1.z.string().describe("Description of the rule you want to generate"),
352
+ }, async ({ query }) => {
353
+ const payload = {
354
+ agent: "rule_generator",
355
+ query,
356
+ };
357
+ const data = await makeImpartRequest("sparkle", undefined, "POST", payload);
358
+ if (!data) {
359
+ return {
360
+ content: [
361
+ { type: "text", text: "Error: Failed to generate rule script" },
362
+ ],
363
+ };
364
+ }
365
+ if (!data.output) {
366
+ return {
367
+ content: [
368
+ {
369
+ type: "text",
370
+ text: "Error: No output received from the Sparkle API",
371
+ },
372
+ ],
373
+ };
374
+ }
375
+ return {
376
+ content: [
377
+ { type: "text", text: `Generated Rule Script:\n\n${data.output}` },
378
+ ],
379
+ };
380
+ });
381
+ server.tool("validate_rules_script", "Validate a rules script", {
382
+ src: zod_1.z
383
+ .string()
384
+ .describe("The base64-encoded source code of the rules script to validate"),
385
+ lang: zod_1.z
386
+ .string()
387
+ .default("assemblyscript")
388
+ .describe("The language of the rules script"),
389
+ }, async ({ src, lang }) => {
390
+ if (!src) {
391
+ return {
392
+ content: [
393
+ {
394
+ type: "text",
395
+ text: "Error: The source code (src) is required and must be base64 encoded.",
396
+ },
397
+ ],
398
+ };
399
+ }
400
+ const payload = {
401
+ src,
402
+ lang,
403
+ };
404
+ const data = await makeImpartRequest("rules_script_validate", undefined, "POST", payload);
405
+ if (!data) {
406
+ return {
407
+ content: [{ type: "text", text: "Failed to validate rules script" }],
408
+ };
409
+ }
410
+ const diagnostics = data.diagnostics || [];
411
+ if (diagnostics.length === 0) {
412
+ return {
413
+ content: [
414
+ {
415
+ type: "text",
416
+ text: "Validation successful! No errors or warnings found.",
417
+ },
418
+ ],
419
+ };
420
+ }
421
+ const formattedDiagnostics = diagnostics.map((diagnostic) => `${diagnostic.severity.toUpperCase()} at line ${diagnostic.line}, column ${diagnostic.column}: ${diagnostic.message}`);
422
+ return {
423
+ content: [
424
+ {
425
+ type: "text",
426
+ text: "Validation completed with the following issues:\n" +
427
+ formattedDiagnostics.join("\n"),
428
+ },
429
+ ],
430
+ };
431
+ });
432
+ server.tool("list_endpoints", "Get an inventory of endpoints for the organization", {
433
+ max_results: zod_1.z
434
+ .number()
435
+ .default(100)
436
+ .describe("The maximum number of results to return"),
437
+ }, async ({ max_results }) => {
438
+ const queryParams = { max_results };
439
+ const data = await makeImpartRequest("endpoints", queryParams);
440
+ if (!data) {
441
+ return {
442
+ content: [
443
+ { type: "text", text: "Unable to fetch endpoints: Unknown error" },
444
+ ],
445
+ };
446
+ }
447
+ const endpoints = data.items || [];
448
+ if (endpoints.length === 0) {
449
+ return {
450
+ content: [
451
+ { type: "text", text: "No endpoints found for this organization." },
452
+ ],
453
+ };
454
+ }
455
+ const formattedEndpoints = endpoints.map((endpoint) => [
456
+ `ID: ${endpoint.id}`,
457
+ `Spec ID: ${endpoint.spec_id}`,
458
+ `Path: ${endpoint.path}`,
459
+ `Method: ${endpoint.method}`,
460
+ `Source: ${endpoint.source}`,
461
+ `Orphaned: ${endpoint.orphaned}`,
462
+ "---",
463
+ ].join("\n"));
464
+ return {
465
+ content: [{ type: "text", text: formattedEndpoints.join("\n") }],
466
+ };
467
+ });
468
+ server.tool("list_tags", "Get a list of tags for your Impart organization", {
469
+ max_results: zod_1.z
470
+ .number()
471
+ .default(100)
472
+ .describe("The maximum number of results to return"),
473
+ }, async ({ max_results }) => {
474
+ const queryParams = { max_results };
475
+ const data = await makeImpartRequest("tags", queryParams);
476
+ if (!data) {
477
+ return {
478
+ content: [
479
+ { type: "text", text: "Unable to fetch tags: Unknown error" },
480
+ ],
481
+ };
482
+ }
483
+ const tags = data.items || [];
484
+ if (tags.length === 0) {
485
+ return {
486
+ content: [
487
+ { type: "text", text: "No tags found for this organization." },
488
+ ],
489
+ };
490
+ }
491
+ const formattedTags = tags.map((tag) => [
492
+ `Name: ${tag.name}`,
493
+ `Display Name: ${tag.display_name}`,
494
+ `Type: ${tag.type}`,
495
+ `Description: ${tag.description ?? "N/A"}`,
496
+ `Risk Statement: ${tag.risk_statement ?? "N/A"}`,
497
+ `External URL: ${tag.external_url ?? "N/A"}`,
498
+ `Category: ${tag.category}`,
499
+ "---",
500
+ ].join("\n"));
501
+ return {
502
+ content: [{ type: "text", text: formattedTags.join("\n") }],
503
+ };
504
+ });
505
+ server.tool("get_tag_metrics", "Get timeseries metrics for one or more tags", {
506
+ metric: zod_1.z
507
+ .array(zod_1.z.string())
508
+ .default(["http-request.count"])
509
+ .describe("List of metric names"),
510
+ from_time: zod_1.z.string().default("-1d").describe("Start time"),
511
+ until_time: zod_1.z.string().default("-0h").describe("End time"),
512
+ spec_id: zod_1.z
513
+ .array(zod_1.z.string())
514
+ .optional()
515
+ .describe("Optional list of spec IDs"),
516
+ collection_id: zod_1.z
517
+ .array(zod_1.z.string())
518
+ .optional()
519
+ .describe("Optional list of collection IDs"),
520
+ endpoint_id: zod_1.z
521
+ .array(zod_1.z.string())
522
+ .optional()
523
+ .describe("Optional list of endpoint IDs"),
524
+ rollup: zod_1.z
525
+ .string()
526
+ .optional()
527
+ .describe("Optional time window rollup resolution"),
528
+ unlearned: zod_1.z
529
+ .string()
530
+ .default("include")
531
+ .describe("How to handle unlearned endpoints"),
532
+ max_results: zod_1.z
533
+ .number()
534
+ .default(100)
535
+ .describe("The maximum number of results to return"),
536
+ }, async ({ metric, from_time, until_time, spec_id, collection_id, endpoint_id, rollup, unlearned, max_results, }) => {
537
+ const queryParams = {
538
+ metric,
539
+ from: from_time,
540
+ until: until_time,
541
+ spec_id,
542
+ collection_id,
543
+ endpoint_id,
544
+ rollup,
545
+ unlearned,
546
+ max_results,
547
+ };
548
+ const data = await makeImpartRequest("timeseries/tags", queryParams);
549
+ if (!data) {
550
+ return {
551
+ content: [
552
+ {
553
+ type: "text",
554
+ text: "Unable to fetch timeseries metrics: Unknown error",
555
+ },
556
+ ],
557
+ };
558
+ }
559
+ const metrics = data.items || [];
560
+ if (metrics.length === 0) {
561
+ return {
562
+ content: [
563
+ {
564
+ type: "text",
565
+ text: "No timeseries metrics found for the specified tags.",
566
+ },
567
+ ],
568
+ };
569
+ }
570
+ const formattedMetrics = metrics.map((metric) => [
571
+ `Metric: ${metric.metric}`,
572
+ `From: ${metric.from}`,
573
+ `Until: ${metric.until}`,
574
+ `Increment: ${metric.inc} seconds`,
575
+ `Total Points: ${metric.total_points}`,
576
+ `Data: ${metric.data.join(", ")}`,
577
+ "---",
578
+ ].join("\n"));
579
+ return {
580
+ content: [{ type: "text", text: formattedMetrics.join("\n") }],
581
+ };
582
+ });
583
+ server.tool("list_observed_hosts", "Get a list of observed hosts for your Impart organization", {
584
+ page: zod_1.z
585
+ .number()
586
+ .default(1)
587
+ .describe("The page of results to return (minimum value: 1)"),
588
+ max_results: zod_1.z
589
+ .number()
590
+ .default(100)
591
+ .describe("The maximum number of results to return"),
592
+ }, async ({ page, max_results }) => {
593
+ const queryParams = {
594
+ page: validatePage(page),
595
+ max_results,
596
+ };
597
+ const data = await makeImpartRequest("observed_hosts", queryParams);
598
+ if (!data) {
599
+ return {
600
+ content: [
601
+ {
602
+ type: "text",
603
+ text: "Unable to fetch observed hosts: Unknown error",
604
+ },
605
+ ],
606
+ };
607
+ }
608
+ const hosts = data.items || [];
609
+ if (hosts.length === 0) {
610
+ return {
611
+ content: [
612
+ {
613
+ type: "text",
614
+ text: "No observed hosts found for this organization.",
615
+ },
616
+ ],
617
+ };
618
+ }
619
+ const formattedHosts = hosts.map((host) => [
620
+ `ID: ${host.id}`,
621
+ `Name: ${host.name || "N/A"}`,
622
+ `IP Address: ${host.ip_address || "N/A"}`,
623
+ `Last Seen: ${host.last_seen || "N/A"}`,
624
+ "---",
625
+ ].join("\n"));
626
+ return {
627
+ content: [{ type: "text", text: formattedHosts.join("\n") }],
628
+ };
629
+ });
630
+ server.tool("get_observed_host", "Get details of a specific observed host", {
631
+ observed_host_id: zod_1.z
632
+ .string()
633
+ .describe("The unique identifier of the observed host"),
634
+ }, async ({ observed_host_id }) => {
635
+ if (!observed_host_id) {
636
+ return {
637
+ content: [
638
+ { type: "text", text: "Error: observed_host_id is required." },
639
+ ],
640
+ };
641
+ }
642
+ const data = await makeImpartRequest(`observed_hosts/${observed_host_id}`);
643
+ if (!data) {
644
+ return {
645
+ content: [
646
+ {
647
+ type: "text",
648
+ text: "Unable to fetch observed host: Unknown error",
649
+ },
650
+ ],
651
+ };
652
+ }
653
+ const formattedHost = [
654
+ `ID: ${data.id}`,
655
+ `Hostname: ${data.hostname ?? "N/A"}`,
656
+ `Port: ${data.port ?? "N/A"}`,
657
+ `Created At: ${data.created_at ?? "N/A"}`,
658
+ `Observed At: ${data.observed_at ?? "N/A"}`,
659
+ `Suspected Healthcheck: ${data.suspected_healthcheck ?? false}`,
660
+ "---",
661
+ "Related IDs:",
662
+ ];
663
+ if (data.related_ids && data.related_ids.length > 0) {
664
+ data.related_ids.forEach((id) => formattedHost.push(` - ${id}`));
665
+ }
666
+ else {
667
+ formattedHost.push(" No related IDs");
668
+ }
669
+ return {
670
+ content: [{ type: "text", text: formattedHost.join("\n") }],
671
+ };
672
+ });
673
+ server.tool("list_specs", "Get a list of specs for your Impart organization", {
674
+ page: zod_1.z
675
+ .number()
676
+ .default(1)
677
+ .describe("The page of results to return (minimum value: 1)"),
678
+ max_results: zod_1.z
679
+ .number()
680
+ .default(100)
681
+ .describe("The maximum number of results to return"),
682
+ }, async ({ page, max_results }) => {
683
+ const queryParams = {
684
+ page: validatePage(page),
685
+ max_results,
686
+ };
687
+ const data = await makeImpartRequest("specs", queryParams);
688
+ if (!data) {
689
+ return {
690
+ content: [
691
+ { type: "text", text: "Unable to fetch specs: Unknown error" },
692
+ ],
693
+ };
694
+ }
695
+ const specs = data.items || [];
696
+ if (specs.length === 0) {
697
+ return {
698
+ content: [
699
+ { type: "text", text: "No specs found for this organization." },
700
+ ],
701
+ };
702
+ }
703
+ const formattedSpecs = specs.map((spec) => [
704
+ `ID: ${spec.id}`,
705
+ `Name: ${spec.name}`,
706
+ `Revision: ${spec.revision}`,
707
+ `Score: ${spec.score}`,
708
+ `Created By: ${spec.created_by}`,
709
+ `Created At: ${spec.created_at}`,
710
+ `Updated By: ${spec.updated_by}`,
711
+ `Updated At: ${spec.updated_at}`,
712
+ "---",
713
+ ].join("\n"));
714
+ return {
715
+ content: [{ type: "text", text: formattedSpecs.join("\n") }],
716
+ };
717
+ });
718
+ server.tool("get_spec", "Get details of a specific spec", {
719
+ spec_id: zod_1.z.string().describe("The unique identifier of the spec"),
720
+ revision: zod_1.z.number().optional().describe("The specific revision to fetch"),
721
+ }, async ({ spec_id, revision }) => {
722
+ if (!spec_id) {
723
+ return {
724
+ content: [{ type: "text", text: "Error: spec_id is required." }],
725
+ };
726
+ }
727
+ const queryParams = revision ? { revision } : undefined;
728
+ const data = await makeImpartRequest(`specs/${spec_id}`, queryParams);
729
+ if (!data) {
730
+ return {
731
+ content: [
732
+ { type: "text", text: "Unable to fetch spec: Unknown error" },
733
+ ],
734
+ };
735
+ }
736
+ const formattedSpec = [
737
+ `ID: ${data.id}`,
738
+ `Name: ${data.name}`,
739
+ `Revision: ${data.revision}`,
740
+ `Score: ${data.score}`,
741
+ `Created By: ${data.created_by}`,
742
+ `Created At: ${data.created_at}`,
743
+ `Updated By: ${data.updated_by}`,
744
+ `Updated At: ${data.updated_at}`,
745
+ "---",
746
+ "Revisions:",
747
+ ];
748
+ if (data.revisions && data.revisions.length > 0) {
749
+ data.revisions.forEach((revision) => {
750
+ formattedSpec.push(` Revision: ${revision.revision}`, ` Created By: ${revision.created_by}`, ` Created At: ${revision.created_at}`, "---");
751
+ });
752
+ }
753
+ formattedSpec.push(`Specification (Base64 Encoded):\n${data.spec ?? "N/A"}`);
754
+ return {
755
+ content: [{ type: "text", text: formattedSpec.join("\n") }],
756
+ };
757
+ });
758
+ server.tool("list_api_bindings", "Get a list of API bindings for the organization", {
759
+ page: zod_1.z
760
+ .number()
761
+ .default(1)
762
+ .describe("The page of results to return (minimum value: 1)"),
763
+ max_results: zod_1.z
764
+ .number()
765
+ .default(100)
766
+ .describe("The maximum number of results to return"),
767
+ }, async ({ page, max_results }) => {
768
+ const queryParams = {
769
+ page: validatePage(page),
770
+ max_results,
771
+ };
772
+ const data = await makeImpartRequest("api_bindings", queryParams);
773
+ if (!data) {
774
+ return {
775
+ content: [
776
+ { type: "text", text: "Unable to fetch API bindings: Unknown error" },
777
+ ],
778
+ };
779
+ }
780
+ const bindings = data.items || [];
781
+ if (bindings.length === 0) {
782
+ return {
783
+ content: [
784
+ {
785
+ type: "text",
786
+ text: "No API bindings found for this organization.",
787
+ },
788
+ ],
789
+ };
790
+ }
791
+ const formattedBindings = bindings.map((binding) => [
792
+ `ID: ${binding.id}`,
793
+ `Name: ${binding.name}`,
794
+ `Type: ${binding.type}`,
795
+ `Host: ${binding.host}`,
796
+ `Status: ${binding.status}`,
797
+ `Created At: ${binding.created_at}`,
798
+ "---",
799
+ ].join("\n"));
800
+ return {
801
+ content: [{ type: "text", text: formattedBindings.join("\n") }],
802
+ };
803
+ });
804
+ server.tool("create_api_binding", "Create a new API binding for the organization", {
805
+ name: zod_1.z.string().describe("The name of the API binding"),
806
+ binding_type: zod_1.z
807
+ .string()
808
+ .describe("The type of binding ('apiKey', 'basic', 'bearer', or 'oauth2')"),
809
+ host: zod_1.z.string().describe("The host to bind to"),
810
+ api_binding_source: zod_1.z
811
+ .string()
812
+ .describe("Location of the binding ('header', 'query', or 'cookie')"),
813
+ binding_value: zod_1.z.string().describe("The value of the binding"),
814
+ description: zod_1.z
815
+ .string()
816
+ .optional()
817
+ .describe("Optional description of the binding"),
818
+ patch_operations: zod_1.z
819
+ .array(zod_1.z.record(zod_1.z.any()))
820
+ .optional()
821
+ .describe("Optional list of JSON patch operations"),
822
+ enable_learning: zod_1.z
823
+ .boolean()
824
+ .default(true)
825
+ .describe("Whether to enable learning for this binding"),
826
+ }, async ({ name, binding_type, host, api_binding_source, binding_value, description, patch_operations, enable_learning, }) => {
827
+ const payload = {
828
+ name,
829
+ type: binding_type,
830
+ host,
831
+ source: api_binding_source,
832
+ value: binding_value,
833
+ description,
834
+ patch_operations: patch_operations ?? [],
835
+ enable_learning,
836
+ };
837
+ const data = await makeImpartRequest("api_bindings", undefined, "POST", payload);
838
+ if (!data) {
839
+ return {
840
+ content: [{ type: "text", text: "Failed to create API binding" }],
841
+ };
842
+ }
843
+ const formattedBinding = [
844
+ "API Binding created successfully:",
845
+ `ID: ${data.id}`,
846
+ `Name: ${data.name}`,
847
+ `Type: ${data.type}`,
848
+ `Host: ${data.host}`,
849
+ `Source: ${data.source}`,
850
+ `Status: ${data.status}`,
851
+ `Description: ${data.description ?? "N/A"}`,
852
+ `Learning Enabled: ${data.enable_learning}`,
853
+ `Created At: ${data.created_at}`,
854
+ "---",
855
+ ].join("\n");
856
+ return {
857
+ content: [{ type: "text", text: formattedBinding }],
858
+ };
859
+ });
860
+ server.tool("list_lists", "Get a list of lists for the organization", {
861
+ kind: zod_1.z.string().optional().describe("The list kind to query for"),
862
+ subkind: zod_1.z.string().optional().describe("The list subkind to query for"),
863
+ page: zod_1.z
864
+ .number()
865
+ .default(1)
866
+ .describe("The page of results to return (minimum: 1)"),
867
+ max_results: zod_1.z
868
+ .number()
869
+ .default(100)
870
+ .describe("The maximum number of results to return"),
871
+ }, async ({ kind, subkind, page, max_results }) => {
872
+ const queryParams = {
873
+ kind,
874
+ subkind,
875
+ page: validatePage(page),
876
+ max_results,
877
+ };
878
+ const data = await makeImpartRequest("lists", queryParams);
879
+ if (!data) {
880
+ return {
881
+ content: [
882
+ { type: "text", text: "Unable to fetch lists: Unknown error" },
883
+ ],
884
+ };
885
+ }
886
+ const lists = data.items || [];
887
+ if (lists.length === 0) {
888
+ return {
889
+ content: [
890
+ { type: "text", text: "No lists found for this organization." },
891
+ ],
892
+ };
893
+ }
894
+ const formattedLists = lists.map((list) => [
895
+ `ID: ${list.id}`,
896
+ `Name: ${list.name}`,
897
+ `Kind: ${list.kind}`,
898
+ `Subkind: ${list.subkind ?? "N/A"}`,
899
+ `Description: ${list.description ?? "N/A"}`,
900
+ `Created At: ${list.created_at}`,
901
+ `Updated At: ${list.updated_at}`,
902
+ "---",
903
+ ].join("\n"));
904
+ return {
905
+ content: [{ type: "text", text: formattedLists.join("\n") }],
906
+ };
907
+ });
908
+ server.tool("get_list_items", "Get items from a specific list", {
909
+ list_id: zod_1.z.string().describe("The ID of the list"),
910
+ page: zod_1.z
911
+ .number()
912
+ .default(1)
913
+ .describe("The page of results to return (minimum: 1)"),
914
+ max_results: zod_1.z
915
+ .number()
916
+ .default(100)
917
+ .describe("The maximum number of results to return"),
918
+ }, async ({ list_id, page, max_results }) => {
919
+ if (!list_id) {
920
+ return {
921
+ content: [{ type: "text", text: "Error: list_id is required." }],
922
+ };
923
+ }
924
+ const queryParams = {
925
+ page: validatePage(page),
926
+ max_results,
927
+ };
928
+ const data = await makeImpartRequest(`lists/${list_id}/items`, queryParams);
929
+ if (!data) {
930
+ return {
931
+ content: [
932
+ { type: "text", text: "Unable to fetch list items: Unknown error" },
933
+ ],
934
+ };
935
+ }
936
+ const items = data.items || [];
937
+ if (items.length === 0) {
938
+ return {
939
+ content: [{ type: "text", text: "No items found in this list." }],
940
+ };
941
+ }
942
+ const formattedItems = items.map((item) => [`Value: ${item.value}`, `Created At: ${item.created_at}`, "---"].join("\n"));
943
+ return {
944
+ content: [{ type: "text", text: formattedItems.join("\n") }],
945
+ };
946
+ });
947
+ server.tool("create_list", "Creates a new list for the organization", {
948
+ name: zod_1.z.string().describe("Name of the list"),
949
+ kind: zod_1.z.string().describe("The kind of list"),
950
+ subkind: zod_1.z.string().optional().describe("Optional subkind of list"),
951
+ description: zod_1.z.string().optional().describe("Optional description"),
952
+ functionality: zod_1.z
953
+ .string()
954
+ .default("add/remove")
955
+ .describe("List functionality"),
956
+ items: zod_1.z
957
+ .array(zod_1.z.record(zod_1.z.any()))
958
+ .optional()
959
+ .describe("Optional initial list items"),
960
+ }, async ({ name, kind, subkind, description, functionality, items }) => {
961
+ const payload = {
962
+ name,
963
+ kind,
964
+ subkind,
965
+ description,
966
+ functionality,
967
+ items: items ?? [],
968
+ };
969
+ const data = await makeImpartRequest("lists", undefined, "POST", payload);
970
+ if (!data) {
971
+ return {
972
+ content: [{ type: "text", text: "Failed to create list" }],
973
+ };
974
+ }
975
+ const formattedList = [
976
+ "List created successfully:",
977
+ `ID: ${data.id}`,
978
+ `Name: ${data.name}`,
979
+ `Kind: ${data.kind}`,
980
+ `Subkind: ${data.subkind ?? "N/A"}`,
981
+ `Description: ${data.description ?? "N/A"}`,
982
+ `Created At: ${data.created_at}`,
983
+ "---",
984
+ ].join("\n");
985
+ return {
986
+ content: [{ type: "text", text: formattedList }],
987
+ };
988
+ });
989
+ server.tool("update_list_items", "Updates items in a list", {
990
+ list_id: zod_1.z.string().describe("The ID of the list to update"),
991
+ items: zod_1.z
992
+ .array(zod_1.z.record(zod_1.z.any()))
993
+ .describe("The items to update in the list"),
994
+ }, async ({ list_id, items }) => {
995
+ if (!list_id) {
996
+ return {
997
+ content: [{ type: "text", text: "Error: list_id is required." }],
998
+ };
999
+ }
1000
+ const payload = { items };
1001
+ const data = await makeImpartRequest(`lists/${list_id}/items`, undefined, "PATCH", payload);
1002
+ if (!data) {
1003
+ return {
1004
+ content: [{ type: "text", text: "Failed to update list items" }],
1005
+ };
1006
+ }
1007
+ return {
1008
+ content: [{ type: "text", text: "List items updated successfully" }],
1009
+ };
1010
+ });
1011
+ server.tool("create_label", "Creates a new label for the organization", {
1012
+ name: zod_1.z.string().describe("Name of the label"),
1013
+ description: zod_1.z.string().optional().describe("Optional description"),
1014
+ color: zod_1.z.string().default("gray").describe("Label color"),
1015
+ }, async ({ name, description, color }) => {
1016
+ const payload = {
1017
+ name,
1018
+ description,
1019
+ color,
1020
+ };
1021
+ const data = await makeImpartRequest("labels", undefined, "POST", payload);
1022
+ if (!data) {
1023
+ return {
1024
+ content: [{ type: "text", text: "Failed to create label" }],
1025
+ };
1026
+ }
1027
+ const formattedLabel = [
1028
+ "Label created successfully:",
1029
+ `Slug: ${data.slug}`,
1030
+ `Name: ${data.name}`,
1031
+ `Description: ${data.description ?? "N/A"}`,
1032
+ `Color: ${data.color}`,
1033
+ `Created At: ${data.created_at}`,
1034
+ "---",
1035
+ ].join("\n");
1036
+ return {
1037
+ content: [{ type: "text", text: formattedLabel }],
1038
+ };
1039
+ });
1040
+ server.tool("list_labels", "Get a list of labels for the organization", {
1041
+ page: zod_1.z
1042
+ .number()
1043
+ .default(1)
1044
+ .describe("The page of results to return (minimum: 1)"),
1045
+ max_results: zod_1.z
1046
+ .number()
1047
+ .default(100)
1048
+ .describe("The maximum number of results to return"),
1049
+ }, async ({ page, max_results }) => {
1050
+ const queryParams = {
1051
+ page: validatePage(page),
1052
+ max_results,
1053
+ };
1054
+ const data = await makeImpartRequest("labels", queryParams);
1055
+ if (!data) {
1056
+ return {
1057
+ content: [
1058
+ { type: "text", text: "Unable to fetch labels: Unknown error" },
1059
+ ],
1060
+ };
1061
+ }
1062
+ const labels = data.items || [];
1063
+ if (labels.length === 0) {
1064
+ return {
1065
+ content: [
1066
+ { type: "text", text: "No labels found for this organization." },
1067
+ ],
1068
+ };
1069
+ }
1070
+ const formattedLabels = labels.map((label) => [
1071
+ `Slug: ${label.slug}`,
1072
+ `Name: ${label.name}`,
1073
+ `Description: ${label.description ?? "N/A"}`,
1074
+ `Color: ${label.color}`,
1075
+ `Created At: ${label.created_at}`,
1076
+ "---",
1077
+ ].join("\n"));
1078
+ return {
1079
+ content: [{ type: "text", text: formattedLabels.join("\n") }],
1080
+ };
1081
+ });
1082
+ async function main() {
1083
+ const transport = new stdio_js_1.StdioServerTransport();
1084
+ await server.connect(transport);
1085
+ console.error("Impart MCP Server running on stdio");
1086
+ }
1087
+ main().catch((error) => {
1088
+ console.error("Fatal error in main():", error);
1089
+ process.exit(1);
1090
+ });
@@ -0,0 +1,158 @@
1
+ export interface BaseResponse {
2
+ error?: string;
3
+ }
4
+ export interface RulesScript {
5
+ id: string;
6
+ name: string;
7
+ description?: string;
8
+ type: string;
9
+ disabled: boolean;
10
+ blocking_effect: string;
11
+ lang: string;
12
+ src?: string;
13
+ revision: number;
14
+ labels: string[];
15
+ created_by: string;
16
+ created_at: string;
17
+ updated_by: string;
18
+ updated_at: string;
19
+ autogenerated_explanation?: string;
20
+ dependencies?: string[];
21
+ }
22
+ export interface RulesScriptRevision {
23
+ revision: number;
24
+ created_by: string;
25
+ created_at: string;
26
+ }
27
+ export interface RulesScriptResponse extends BaseResponse {
28
+ items: RulesScript[];
29
+ }
30
+ export interface RulesScriptDetailResponse extends RulesScript, BaseResponse {
31
+ revisions: RulesScriptRevision[];
32
+ }
33
+ export interface Inspector {
34
+ id: string;
35
+ version: string;
36
+ last_seen: string;
37
+ }
38
+ export interface InspectorsResponse extends BaseResponse {
39
+ items: Inspector[];
40
+ }
41
+ export interface ObservedHost {
42
+ id: string;
43
+ name: string;
44
+ ip_address: string;
45
+ last_seen: string;
46
+ hostname?: string;
47
+ port?: string;
48
+ created_at?: string;
49
+ observed_at?: string;
50
+ suspected_healthcheck?: boolean;
51
+ related_ids?: string[];
52
+ }
53
+ export interface ObservedHostsResponse extends BaseResponse {
54
+ items: ObservedHost[];
55
+ }
56
+ export interface Spec {
57
+ id: string;
58
+ name: string;
59
+ revision: number;
60
+ score: number;
61
+ created_by: string;
62
+ created_at: string;
63
+ updated_by: string;
64
+ updated_at: string;
65
+ spec?: string;
66
+ }
67
+ export interface SpecRevision {
68
+ revision: number;
69
+ created_by: string;
70
+ created_at: string;
71
+ }
72
+ export interface SpecsResponse extends BaseResponse {
73
+ items: Spec[];
74
+ }
75
+ export interface SpecDetailResponse extends Spec, BaseResponse {
76
+ revisions: SpecRevision[];
77
+ }
78
+ export interface ApiBinding {
79
+ id: string;
80
+ name: string;
81
+ type: string;
82
+ host: string;
83
+ status: string;
84
+ created_at: string;
85
+ source: string;
86
+ value: string;
87
+ description?: string;
88
+ enable_learning: boolean;
89
+ patch_operations?: Record<string, unknown>[];
90
+ }
91
+ export interface ApiBindingsResponse extends BaseResponse {
92
+ items: ApiBinding[];
93
+ }
94
+ export interface List {
95
+ id: string;
96
+ name: string;
97
+ kind: string;
98
+ subkind?: string;
99
+ description?: string;
100
+ functionality: string;
101
+ created_at: string;
102
+ updated_at: string;
103
+ items?: Record<string, unknown>[];
104
+ }
105
+ export interface ListsResponse extends BaseResponse {
106
+ items: List[];
107
+ }
108
+ export interface ListItem {
109
+ value: string;
110
+ created_at: string;
111
+ }
112
+ export interface ListItemsResponse extends BaseResponse {
113
+ items: ListItem[];
114
+ }
115
+ export interface Label {
116
+ slug: string;
117
+ name: string;
118
+ description?: string;
119
+ color: string;
120
+ created_at: string;
121
+ }
122
+ export interface LabelsResponse extends BaseResponse {
123
+ items: Label[];
124
+ }
125
+ export interface Tag {
126
+ name: string;
127
+ display_name: string;
128
+ type: string;
129
+ description?: string;
130
+ risk_statement?: string;
131
+ external_url?: string;
132
+ category: string;
133
+ }
134
+ export interface TagsResponse extends BaseResponse {
135
+ items: Tag[];
136
+ }
137
+ export interface TimeseriesMetric {
138
+ metric: string;
139
+ from: string;
140
+ until: string;
141
+ inc: number;
142
+ total_points: number;
143
+ data: number[];
144
+ }
145
+ export interface TimeseriesResponse extends BaseResponse {
146
+ items: TimeseriesMetric[];
147
+ }
148
+ export interface Endpoint {
149
+ id: string;
150
+ spec_id: string;
151
+ path: string;
152
+ method: string;
153
+ source: string;
154
+ orphaned: boolean;
155
+ }
156
+ export interface EndpointsResponse extends BaseResponse {
157
+ items: Endpoint[];
158
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@impart-security/impart-mcp",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Model Context Protocol (MCP) implementation for interacting with Impart's API",
5
5
  "author": "Impart Security",
6
6
  "license": "Apache-2.0",