@iris-eval/mcp-server 0.4.4 → 0.4.5
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 +55 -1
- package/dist/audit-log-reader.js +1 -1
- package/dist/config/defaults.d.ts +1 -0
- package/dist/config/defaults.js +3 -0
- package/dist/custom-rule-store.js +109 -2
- package/dist/dashboard/assets/index-CIKsbEhq.js +10 -0
- package/dist/dashboard/index.html +1 -1
- package/dist/dashboard/routes/rules.js +1 -1
- package/dist/dashboard/server.js +16 -3
- package/dist/dashboard/validation.d.ts +36 -62
- package/dist/eval/citation-verify/resolve.js +101 -15
- package/dist/eval/rules/config-keys.d.ts +14 -0
- package/dist/eval/rules/config-keys.js +43 -0
- package/dist/eval/rules/custom.js +43 -14
- package/dist/eval/rules/relevance.d.ts +1 -0
- package/dist/eval/rules/relevance.js +3 -1
- package/dist/eval/rules/safety.d.ts +5 -0
- package/dist/eval/rules/safety.js +4 -2
- package/dist/index.js +3 -1
- package/dist/middleware/error-handler.js +19 -1
- package/dist/otel/mapper.js +2 -1
- package/dist/preferences.d.ts +43 -93
- package/dist/tools/deploy-rule.js +2 -2
- package/dist/tools/evaluate-output.js +1 -1
- package/dist/tools/log-trace.js +3 -3
- package/dist/transport/http.js +68 -4
- package/package.json +10 -5
- package/server.json +1 -1
- package/dist/dashboard/assets/index-DNflCqmJ.js +0 -12
package/dist/preferences.d.ts
CHANGED
|
@@ -1,108 +1,58 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
declare const MomentFiltersSchema: z.ZodObject<{
|
|
3
3
|
agentName: z.ZodOptional<z.ZodString>;
|
|
4
|
-
verdict: z.ZodOptional<z.ZodEnum<
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
significanceKind?: "safety-violation" | "cost-spike" | "first-failure" | "novel-pattern" | "rule-collision" | "normal-pass" | "normal-fail" | undefined;
|
|
10
|
-
}, {
|
|
11
|
-
verdict?: "pass" | "fail" | "partial" | "unevaluated" | undefined;
|
|
12
|
-
agentName?: string | undefined;
|
|
13
|
-
significanceKind?: "safety-violation" | "cost-spike" | "first-failure" | "novel-pattern" | "rule-collision" | "normal-pass" | "normal-fail" | undefined;
|
|
14
|
-
}>;
|
|
15
|
-
export declare const PreferencesSchema: z.ZodObject<{
|
|
16
|
-
autoLaunch: z.ZodDefault<z.ZodBoolean>;
|
|
17
|
-
firstSeen: z.ZodOptional<z.ZodString>;
|
|
18
|
-
dismissedBanners: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
19
|
-
/** Theme override; "system" defers to prefers-color-scheme. v0.4. */
|
|
20
|
-
theme: z.ZodDefault<z.ZodEnum<["dark", "light", "system"]>>;
|
|
21
|
-
/** Last filter set used on /moments — applied on next visit when the URL has no filter params. v0.4. */
|
|
22
|
-
momentFilters: z.ZodDefault<z.ZodObject<{
|
|
23
|
-
agentName: z.ZodOptional<z.ZodString>;
|
|
24
|
-
verdict: z.ZodOptional<z.ZodEnum<["pass", "fail", "partial", "unevaluated"]>>;
|
|
25
|
-
significanceKind: z.ZodOptional<z.ZodEnum<["safety-violation", "cost-spike", "first-failure", "novel-pattern", "rule-collision", "normal-pass", "normal-fail"]>>;
|
|
26
|
-
}, "strict", z.ZodTypeAny, {
|
|
27
|
-
verdict?: "pass" | "fail" | "partial" | "unevaluated" | undefined;
|
|
28
|
-
agentName?: string | undefined;
|
|
29
|
-
significanceKind?: "safety-violation" | "cost-spike" | "first-failure" | "novel-pattern" | "rule-collision" | "normal-pass" | "normal-fail" | undefined;
|
|
30
|
-
}, {
|
|
31
|
-
verdict?: "pass" | "fail" | "partial" | "unevaluated" | undefined;
|
|
32
|
-
agentName?: string | undefined;
|
|
33
|
-
significanceKind?: "safety-violation" | "cost-spike" | "first-failure" | "novel-pattern" | "rule-collision" | "normal-pass" | "normal-fail" | undefined;
|
|
4
|
+
verdict: z.ZodOptional<z.ZodEnum<{
|
|
5
|
+
pass: "pass";
|
|
6
|
+
fail: "fail";
|
|
7
|
+
partial: "partial";
|
|
8
|
+
unevaluated: "unevaluated";
|
|
34
9
|
}>>;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
/** ISO timestamp of last notifications-popover opened — drives unread badge. */
|
|
44
|
-
notificationsLastSeen: z.ZodOptional<z.ZodString>;
|
|
45
|
-
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
46
|
-
autoLaunch: z.ZodDefault<z.ZodBoolean>;
|
|
47
|
-
firstSeen: z.ZodOptional<z.ZodString>;
|
|
48
|
-
dismissedBanners: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
49
|
-
/** Theme override; "system" defers to prefers-color-scheme. v0.4. */
|
|
50
|
-
theme: z.ZodDefault<z.ZodEnum<["dark", "light", "system"]>>;
|
|
51
|
-
/** Last filter set used on /moments — applied on next visit when the URL has no filter params. v0.4. */
|
|
52
|
-
momentFilters: z.ZodDefault<z.ZodObject<{
|
|
53
|
-
agentName: z.ZodOptional<z.ZodString>;
|
|
54
|
-
verdict: z.ZodOptional<z.ZodEnum<["pass", "fail", "partial", "unevaluated"]>>;
|
|
55
|
-
significanceKind: z.ZodOptional<z.ZodEnum<["safety-violation", "cost-spike", "first-failure", "novel-pattern", "rule-collision", "normal-pass", "normal-fail"]>>;
|
|
56
|
-
}, "strict", z.ZodTypeAny, {
|
|
57
|
-
verdict?: "pass" | "fail" | "partial" | "unevaluated" | undefined;
|
|
58
|
-
agentName?: string | undefined;
|
|
59
|
-
significanceKind?: "safety-violation" | "cost-spike" | "first-failure" | "novel-pattern" | "rule-collision" | "normal-pass" | "normal-fail" | undefined;
|
|
60
|
-
}, {
|
|
61
|
-
verdict?: "pass" | "fail" | "partial" | "unevaluated" | undefined;
|
|
62
|
-
agentName?: string | undefined;
|
|
63
|
-
significanceKind?: "safety-violation" | "cost-spike" | "first-failure" | "novel-pattern" | "rule-collision" | "normal-pass" | "normal-fail" | undefined;
|
|
10
|
+
significanceKind: z.ZodOptional<z.ZodEnum<{
|
|
11
|
+
"safety-violation": "safety-violation";
|
|
12
|
+
"cost-spike": "cost-spike";
|
|
13
|
+
"first-failure": "first-failure";
|
|
14
|
+
"novel-pattern": "novel-pattern";
|
|
15
|
+
"rule-collision": "rule-collision";
|
|
16
|
+
"normal-pass": "normal-pass";
|
|
17
|
+
"normal-fail": "normal-fail";
|
|
64
18
|
}>>;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
/** Decision Moments hidden from the timeline by user action. v0.4. */
|
|
68
|
-
archivedMoments: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
69
|
-
/** Density mode for chrome (Design System v2.A). 'compact' default per R2.3. */
|
|
70
|
-
density: z.ZodDefault<z.ZodEnum<["compact", "comfortable"]>>;
|
|
71
|
-
/** Sidebar collapsed (icon-only at 64px) vs expanded (256px). Default expanded per R2.4. */
|
|
72
|
-
sidebarCollapsed: z.ZodDefault<z.ZodBoolean>;
|
|
73
|
-
/** ISO timestamp of last notifications-popover opened — drives unread badge. */
|
|
74
|
-
notificationsLastSeen: z.ZodOptional<z.ZodString>;
|
|
75
|
-
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
19
|
+
}, z.core.$strict>;
|
|
20
|
+
export declare const PreferencesSchema: z.ZodObject<{
|
|
76
21
|
autoLaunch: z.ZodDefault<z.ZodBoolean>;
|
|
77
22
|
firstSeen: z.ZodOptional<z.ZodString>;
|
|
78
|
-
dismissedBanners: z.ZodDefault<z.ZodArray<z.ZodString
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
23
|
+
dismissedBanners: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
24
|
+
theme: z.ZodDefault<z.ZodEnum<{
|
|
25
|
+
light: "light";
|
|
26
|
+
dark: "dark";
|
|
27
|
+
system: "system";
|
|
28
|
+
}>>;
|
|
82
29
|
momentFilters: z.ZodDefault<z.ZodObject<{
|
|
83
30
|
agentName: z.ZodOptional<z.ZodString>;
|
|
84
|
-
verdict: z.ZodOptional<z.ZodEnum<
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
31
|
+
verdict: z.ZodOptional<z.ZodEnum<{
|
|
32
|
+
pass: "pass";
|
|
33
|
+
fail: "fail";
|
|
34
|
+
partial: "partial";
|
|
35
|
+
unevaluated: "unevaluated";
|
|
36
|
+
}>>;
|
|
37
|
+
significanceKind: z.ZodOptional<z.ZodEnum<{
|
|
38
|
+
"safety-violation": "safety-violation";
|
|
39
|
+
"cost-spike": "cost-spike";
|
|
40
|
+
"first-failure": "first-failure";
|
|
41
|
+
"novel-pattern": "novel-pattern";
|
|
42
|
+
"rule-collision": "rule-collision";
|
|
43
|
+
"normal-pass": "normal-pass";
|
|
44
|
+
"normal-fail": "normal-fail";
|
|
45
|
+
}>>;
|
|
46
|
+
}, z.core.$strict>>;
|
|
47
|
+
dismissedTours: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
48
|
+
archivedMoments: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
49
|
+
density: z.ZodDefault<z.ZodEnum<{
|
|
50
|
+
compact: "compact";
|
|
51
|
+
comfortable: "comfortable";
|
|
94
52
|
}>>;
|
|
95
|
-
/** Tour ids the user has completed or dismissed. v0.4. */
|
|
96
|
-
dismissedTours: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
97
|
-
/** Decision Moments hidden from the timeline by user action. v0.4. */
|
|
98
|
-
archivedMoments: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
99
|
-
/** Density mode for chrome (Design System v2.A). 'compact' default per R2.3. */
|
|
100
|
-
density: z.ZodDefault<z.ZodEnum<["compact", "comfortable"]>>;
|
|
101
|
-
/** Sidebar collapsed (icon-only at 64px) vs expanded (256px). Default expanded per R2.4. */
|
|
102
53
|
sidebarCollapsed: z.ZodDefault<z.ZodBoolean>;
|
|
103
|
-
/** ISO timestamp of last notifications-popover opened — drives unread badge. */
|
|
104
54
|
notificationsLastSeen: z.ZodOptional<z.ZodString>;
|
|
105
|
-
}, z.
|
|
55
|
+
}, z.core.$loose>;
|
|
106
56
|
export type Preferences = z.infer<typeof PreferencesSchema>;
|
|
107
57
|
export type MomentFilters = z.infer<typeof MomentFiltersSchema>;
|
|
108
58
|
export interface PreferenceState {
|
|
@@ -24,7 +24,7 @@ const CustomRuleDefinitionSchema = z.object({
|
|
|
24
24
|
'json_schema',
|
|
25
25
|
'cost_threshold',
|
|
26
26
|
]),
|
|
27
|
-
config: z.record(z.unknown()),
|
|
27
|
+
config: z.record(z.string(), z.unknown()),
|
|
28
28
|
weight: z.number().optional(),
|
|
29
29
|
});
|
|
30
30
|
const inputSchema = {
|
|
@@ -63,7 +63,7 @@ export function registerDeployRuleTool(server, customRuleStore) {
|
|
|
63
63
|
'',
|
|
64
64
|
"Don't use to VALIDATE a rule before committing — deploy writes immediately. Use the dashboard's preview endpoint (POST /api/v1/rules/custom/preview) for dry-run validation against sample output. Don't use to EDIT an existing rule — this call only creates; edits require a dedicated flow (coming in v0.5). To update a rule today: delete_rule then deploy_rule with the new definition.",
|
|
65
65
|
'',
|
|
66
|
-
'Parameters. name is 1-120 chars (Zod-enforced min/max); appears in eval_result rule_results so make it human-readable. description is optional, max 500 chars (used in dashboard tooltips). evalType determines WHEN the rule fires (must match the eval_type your evaluate_output calls use; e.g., a "completeness" rule fires on every evaluate_output where eval_type="completeness" OR eval_type="custom"). severity affects dashboard sort + audit log signal but does NOT affect scoring (scoring uses the rule\'s weight). definition.type and definition.config must match (e.g., regex_match needs config.pattern; cost_threshold needs config.
|
|
66
|
+
'Parameters. name is 1-120 chars (Zod-enforced min/max); appears in eval_result rule_results so make it human-readable. description is optional, max 500 chars (used in dashboard tooltips). evalType determines WHEN the rule fires (must match the eval_type your evaluate_output calls use; e.g., a "completeness" rule fires on every evaluate_output where eval_type="completeness" OR eval_type="custom"). severity affects dashboard sort + audit log signal but does NOT affect scoring (scoring uses the rule\'s weight). definition.type and definition.config must match (e.g., regex_match needs config.pattern; cost_threshold needs config.max_cost; min_length needs config.min_length; max_length needs config.max_length; contains_keywords/excludes_keywords need config.keywords). Invalid configs are now REJECTED at deploy time with the offending field named, instead of deploying and then failing every evaluation. sourceMomentId is optional but recommended (preserves workflow-inversion provenance from Make-This-A-Rule composer). Defaults: severity="medium".',
|
|
67
67
|
'',
|
|
68
68
|
"Error modes. Throws 400 on invalid definition (Zod rejects — e.g., regex that fails safe-regex2 ReDoS check, or length > 1000 chars). Throws 400 on empty `name`. Throws 400 if the eval category mismatches the definition type. Returns 429 when HTTP rate limit exceeded. File-write failures (disk full, read-only fs) propagate as 500; the audit log is best-effort and does not block deploy.",
|
|
69
69
|
].join('\n'),
|
|
@@ -6,7 +6,7 @@ const CustomRuleSchema = z.object({
|
|
|
6
6
|
'regex_match', 'regex_no_match', 'min_length', 'max_length',
|
|
7
7
|
'contains_keywords', 'excludes_keywords', 'json_schema', 'cost_threshold',
|
|
8
8
|
]),
|
|
9
|
-
config: z.record(z.unknown()),
|
|
9
|
+
config: z.record(z.string(), z.unknown()),
|
|
10
10
|
weight: z.number().optional(),
|
|
11
11
|
});
|
|
12
12
|
const inputSchema = {
|
package/dist/tools/log-trace.js
CHANGED
|
@@ -18,11 +18,11 @@ const SpanSchema = z.object({
|
|
|
18
18
|
status_message: z.string().optional(),
|
|
19
19
|
start_time: z.string(),
|
|
20
20
|
end_time: z.string().optional(),
|
|
21
|
-
attributes: z.record(z.unknown()).optional(),
|
|
21
|
+
attributes: z.record(z.string(), z.unknown()).optional(),
|
|
22
22
|
events: z.array(z.object({
|
|
23
23
|
name: z.string(),
|
|
24
24
|
timestamp: z.string(),
|
|
25
|
-
attributes: z.record(z.unknown()).optional(),
|
|
25
|
+
attributes: z.record(z.string(), z.unknown()).optional(),
|
|
26
26
|
})).optional(),
|
|
27
27
|
});
|
|
28
28
|
const TokenUsageSchema = z.object({
|
|
@@ -39,7 +39,7 @@ const inputSchema = {
|
|
|
39
39
|
latency_ms: z.number().optional().describe('Total execution time in milliseconds (end-to-end agent latency)'),
|
|
40
40
|
token_usage: TokenUsageSchema.optional().describe('Token usage breakdown (prompt/completion/total — used for cost analysis)'),
|
|
41
41
|
cost_usd: z.number().optional().describe('Total cost in USD — overrides per-span aggregation when provided (treated as authoritative)'),
|
|
42
|
-
metadata: z.record(z.unknown()).optional().describe('Opaque key-value tags (e.g. {requestId, userId, env}) — queryable in dashboard, not via get_traces filters'),
|
|
42
|
+
metadata: z.record(z.string(), z.unknown()).optional().describe('Opaque key-value tags (e.g. {requestId, userId, env}) — queryable in dashboard, not via get_traces filters'),
|
|
43
43
|
spans: z.array(SpanSchema).optional().describe('Detailed execution spans (hierarchical span tree with timings, attributes, events)'),
|
|
44
44
|
timestamp: z.string().optional().describe('Trace timestamp (ISO 8601); defaults to now() when omitted'),
|
|
45
45
|
};
|
package/dist/transport/http.js
CHANGED
|
@@ -23,7 +23,74 @@ export async function createHttpTransport(mcpServer, config, logger) {
|
|
|
23
23
|
});
|
|
24
24
|
// Authentication
|
|
25
25
|
app.use(createAuthMiddleware(config));
|
|
26
|
-
|
|
26
|
+
/*
|
|
27
|
+
* DNS-rebinding protection (MCP spec: servers MUST validate Origin on
|
|
28
|
+
* HTTP transports; when local, SHOULD bind loopback).
|
|
29
|
+
*
|
|
30
|
+
* iris bound loopback but validated nothing, and `security.apiKey` is
|
|
31
|
+
* undefined by default — so `createAuthMiddleware` is a pass-through. A
|
|
32
|
+
* default `--transport http` server was therefore reachable from any web
|
|
33
|
+
* page the operator visited: the page resolves an attacker-controlled
|
|
34
|
+
* hostname to 127.0.0.1, the browser treats it as same-origin, and the
|
|
35
|
+
* request carries no credentials to be missing. That exposes traces and
|
|
36
|
+
* eval history and allows rule deployment.
|
|
37
|
+
*
|
|
38
|
+
* Origin validation is the fix, and it is safe to switch on by default
|
|
39
|
+
* because the SDK only rejects when an Origin header is PRESENT (see
|
|
40
|
+
* validateRequestHeaders). Real MCP clients — Claude Desktop, Cursor, the
|
|
41
|
+
* CLI — send none, so they are unaffected; browsers always do.
|
|
42
|
+
*
|
|
43
|
+
* Host validation is applied only when bound to loopback. Binding
|
|
44
|
+
* elsewhere is a deliberate network deployment that usually sits behind a
|
|
45
|
+
* proxy rewriting Host, and an exact-match list would break it — the case
|
|
46
|
+
* where the operator has already taken ownership of the boundary.
|
|
47
|
+
*/
|
|
48
|
+
const isLoopbackBind = config.transport.host === '127.0.0.1' ||
|
|
49
|
+
config.transport.host === 'localhost' ||
|
|
50
|
+
config.transport.host === '::1';
|
|
51
|
+
/*
|
|
52
|
+
* Bind FIRST, then build the allowlists from the port actually bound.
|
|
53
|
+
* `config.transport.port` is 0 when the caller wants an ephemeral port
|
|
54
|
+
* (tests and embedders do this), and the OS then picks something else —
|
|
55
|
+
* so allowlists derived from the configured value would contain
|
|
56
|
+
* `127.0.0.1:0` and reject every real request with a 403 that looks
|
|
57
|
+
* exactly like an attack. Routes are registered immediately after, and
|
|
58
|
+
* the port is not discoverable by any client until this function returns.
|
|
59
|
+
*/
|
|
60
|
+
const httpServer = await new Promise((resolve) => {
|
|
61
|
+
const server = app.listen(config.transport.port, config.transport.host, () => resolve(server));
|
|
62
|
+
});
|
|
63
|
+
const address = httpServer.address();
|
|
64
|
+
const port = typeof address === 'object' && address ? address.port : config.transport.port;
|
|
65
|
+
const loopbackOrigins = [
|
|
66
|
+
`http://127.0.0.1:${port}`,
|
|
67
|
+
`http://localhost:${port}`,
|
|
68
|
+
`http://[::1]:${port}`,
|
|
69
|
+
];
|
|
70
|
+
/*
|
|
71
|
+
* The SDK matches origins EXACTLY (`allowedOrigins.includes(origin)`),
|
|
72
|
+
* while iris's own CORS allowlist accepts glob patterns like the shipped
|
|
73
|
+
* default `http://localhost:*`. A pattern entry can never match here, so
|
|
74
|
+
* it is dropped rather than passed through to sit in the list looking
|
|
75
|
+
* effective. The concrete loopback origins added above already express
|
|
76
|
+
* what `http://localhost:*` means for this server's port.
|
|
77
|
+
*
|
|
78
|
+
* Note this rejection is what actually stops the attack. Emitting CORS
|
|
79
|
+
* headers would not: the browser only withholds the RESPONSE, after the
|
|
80
|
+
* server has already executed the request — so a rebound page could still
|
|
81
|
+
* deploy rules or delete traces and simply not read the reply.
|
|
82
|
+
*/
|
|
83
|
+
const configuredOrigins = (config.security.allowedOrigins ?? []).filter((origin) => !origin.includes('*'));
|
|
84
|
+
const allowedOrigins = [...new Set([...loopbackOrigins, ...configuredOrigins])];
|
|
85
|
+
const allowedHosts = isLoopbackBind
|
|
86
|
+
? [`127.0.0.1:${port}`, `localhost:${port}`, `[::1]:${port}`]
|
|
87
|
+
: undefined;
|
|
88
|
+
const transport = new StreamableHTTPServerTransport({
|
|
89
|
+
sessionIdGenerator: () => crypto.randomUUID(),
|
|
90
|
+
enableDnsRebindingProtection: true,
|
|
91
|
+
allowedOrigins,
|
|
92
|
+
...(allowedHosts ? { allowedHosts } : {}),
|
|
93
|
+
});
|
|
27
94
|
// Rate limiter for MCP POST/DELETE (not GET — SSE streaming)
|
|
28
95
|
const mcpLimiter = createMcpRateLimiter(config);
|
|
29
96
|
app.post('/mcp', mcpLimiter, async (req, res) => {
|
|
@@ -37,8 +104,5 @@ export async function createHttpTransport(mcpServer, config, logger) {
|
|
|
37
104
|
});
|
|
38
105
|
// Error handler (must be last)
|
|
39
106
|
app.use(createErrorHandler(logger));
|
|
40
|
-
const httpServer = await new Promise((resolve) => {
|
|
41
|
-
const server = app.listen(config.transport.port, config.transport.host, () => resolve(server));
|
|
42
|
-
});
|
|
43
107
|
return { transport, httpServer };
|
|
44
108
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iris-eval/mcp-server",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
4
4
|
"description": "The agent eval standard for MCP. Score every agent output for quality, safety, and cost.",
|
|
5
5
|
"mcpName": "io.github.iris-eval/mcp-server",
|
|
6
6
|
"type": "module",
|
|
@@ -76,27 +76,32 @@
|
|
|
76
76
|
"node": ">=20.0.0"
|
|
77
77
|
},
|
|
78
78
|
"overrides": {
|
|
79
|
-
"
|
|
79
|
+
"brace-expansion": "^5.0.7",
|
|
80
|
+
"fast-uri": "^3.1.5",
|
|
81
|
+
"ip-address": "^10.4.0",
|
|
82
|
+
"postcss": "^8.5.25",
|
|
83
|
+
"@hono/node-server": "^2.1.0"
|
|
80
84
|
},
|
|
81
85
|
"dependencies": {
|
|
82
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
86
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
83
87
|
"better-sqlite3": "^12.8.0",
|
|
84
88
|
"express": "^5.1.0",
|
|
85
89
|
"express-rate-limit": "^8.3.2",
|
|
86
90
|
"helmet": "^8.1.0",
|
|
87
91
|
"pino": "^10.3.1",
|
|
88
92
|
"safe-regex2": "^5.1.0",
|
|
89
|
-
"zod": "^
|
|
93
|
+
"zod": "^4.4.3"
|
|
90
94
|
},
|
|
91
95
|
"devDependencies": {
|
|
92
96
|
"@playwright/test": "^1.59.1",
|
|
93
97
|
"@types/better-sqlite3": "^7.6.0",
|
|
94
98
|
"@types/express": "^5.0.0",
|
|
95
|
-
"@types/node": "^
|
|
99
|
+
"@types/node": "^26.1.1",
|
|
96
100
|
"@typescript-eslint/eslint-plugin": "^8.58.0",
|
|
97
101
|
"@typescript-eslint/parser": "^8.58.0",
|
|
98
102
|
"@vitest/coverage-v8": "^4.1.1",
|
|
99
103
|
"eslint": "^10.2.0",
|
|
104
|
+
"fast-check": "^4.8.0",
|
|
100
105
|
"prettier": "^3.0.0",
|
|
101
106
|
"tsx": "^4.0.0",
|
|
102
107
|
"typescript": "^5.7.0",
|