@iris-eval/mcp-server 0.1.2 → 0.1.4

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.
@@ -1 +1 @@
1
- :root{--bg-primary: #0a0a0b;--bg-secondary: #141416;--bg-tertiary: #1c1c1f;--bg-hover: #252528;--text-primary: #fafafa;--text-secondary: #a1a1aa;--text-muted: #71717a;--accent-primary: #6366f1;--accent-primary-hover: #818cf8;--accent-success: #22c55e;--accent-error: #ef4444;--accent-warning: #f59e0b;--accent-tool: #3b82f6;--accent-llm: #a855f7;--border-color: #27272a;--border-radius: 8px;--border-radius-sm: 4px;--border-radius-lg: 12px;--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;--font-mono: "JetBrains Mono", "Fira Code", monospace;--font-size-xs: .75rem;--font-size-sm: .875rem;--font-size-base: 1rem;--font-size-lg: 1.125rem;--font-size-xl: 1.25rem;--font-size-2xl: 1.5rem;--font-size-3xl: 2rem;--space-1: .25rem;--space-2: .5rem;--space-3: .75rem;--space-4: 1rem;--space-5: 1.25rem;--space-6: 1.5rem;--space-8: 2rem;--space-10: 2.5rem;--space-12: 3rem;--shadow-sm: 0 1px 2px rgba(0, 0, 0, .3);--shadow-md: 0 4px 6px rgba(0, 0, 0, .4);--shadow-lg: 0 10px 15px rgba(0, 0, 0, .5);--transition-fast: .15s ease;--transition-base: .2s ease}*,*:before,*:after{box-sizing:border-box;margin:0;padding:0}html,body,#root{height:100%;width:100%}body{font-family:var(--font-sans);font-size:var(--font-size-base);color:var(--text-primary);background-color:var(--bg-primary);line-height:1.5;-webkit-font-smoothing:antialiased}a{color:var(--accent-primary);text-decoration:none}a:hover{color:var(--accent-primary-hover)}button{cursor:pointer;font-family:inherit}input,select{font-family:inherit;font-size:inherit}code,pre{font-family:var(--font-mono)}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{background:var(--bg-primary)}::-webkit-scrollbar-thumb{background:var(--border-color);border-radius:4px}::-webkit-scrollbar-thumb:hover{background:var(--text-muted)}
1
+ :root{--bg-primary: #0a0a0b;--bg-secondary: #141416;--bg-tertiary: #1c1c1f;--bg-hover: #252528;--text-primary: #fafafa;--text-secondary: #a1a1aa;--text-muted: #71717a;--accent-primary: #0d9488;--accent-primary-hover: #14b8a6;--accent-success: #22c55e;--accent-error: #ef4444;--accent-warning: #f59e0b;--accent-tool: #3b82f6;--accent-llm: #a855f7;--border-color: #27272a;--border-radius: 8px;--border-radius-sm: 4px;--border-radius-lg: 12px;--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;--font-mono: "JetBrains Mono", "Fira Code", monospace;--font-size-xs: .75rem;--font-size-sm: .875rem;--font-size-base: 1rem;--font-size-lg: 1.125rem;--font-size-xl: 1.25rem;--font-size-2xl: 1.5rem;--font-size-3xl: 2rem;--space-1: .25rem;--space-2: .5rem;--space-3: .75rem;--space-4: 1rem;--space-5: 1.25rem;--space-6: 1.5rem;--space-8: 2rem;--space-10: 2.5rem;--space-12: 3rem;--shadow-sm: 0 1px 2px rgba(0, 0, 0, .3);--shadow-md: 0 4px 6px rgba(0, 0, 0, .4);--shadow-lg: 0 10px 15px rgba(0, 0, 0, .5);--transition-fast: .15s ease;--transition-base: .2s ease}*,*:before,*:after{box-sizing:border-box;margin:0;padding:0}html,body,#root{height:100%;width:100%}body{font-family:var(--font-sans);font-size:var(--font-size-base);color:var(--text-primary);background-color:var(--bg-primary);line-height:1.5;-webkit-font-smoothing:antialiased}a{color:var(--accent-primary);text-decoration:none}a:hover{color:var(--accent-primary-hover)}button{cursor:pointer;font-family:inherit}input,select{font-family:inherit;font-size:inherit}code,pre{font-family:var(--font-mono)}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{background:var(--bg-primary)}::-webkit-scrollbar-thumb{background:var(--border-color);border-radius:4px}::-webkit-scrollbar-thumb:hover{background:var(--text-muted)}
@@ -1,5 +1,6 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none">
2
- <circle cx="16" cy="16" r="14" stroke="#6366f1" stroke-width="2.5"/>
3
- <circle cx="16" cy="16" r="7" fill="#6366f1" opacity="0.3"/>
4
- <circle cx="16" cy="16" r="3.5" fill="#6366f1"/>
2
+ <circle cx="16" cy="16" r="14" stroke="#14b8a6" stroke-width="2.5"/>
3
+ <circle cx="16" cy="16" r="8" fill="#0d9488"/>
4
+ <circle cx="16" cy="16" r="3.5" fill="#0a0f0e"/>
5
+ <circle cx="13" cy="13.5" r="1.5" fill="white" opacity="0.6"/>
5
6
  </svg>
@@ -5,8 +5,8 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
7
7
  <title>Iris — Agent Eval & Observability</title>
8
- <script type="module" crossorigin src="/assets/index-BgsGBkem.js"></script>
9
- <link rel="stylesheet" crossorigin href="/assets/index-DsCtYyvh.css">
8
+ <script type="module" crossorigin src="/assets/index-CGWlxM5E.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/index-zuWgVxsu.css">
10
10
  </head>
11
11
  <body>
12
12
  <div id="root"></div>
@@ -1,4 +1,4 @@
1
- import type { IStorageAdapter, DashboardSummary, TraceQueryOptions, TraceQueryResult } from '../types/query.js';
1
+ import type { IStorageAdapter, DashboardSummary, TraceQueryOptions, TraceQueryResult, EvalStatsPeriod, EvalStats, EvalStatsTrendBucket, EvalStatsRuleBreakdown, EvalStatsFailure } from '../types/query.js';
2
2
  import type { Trace, Span } from '../types/trace.js';
3
3
  import type { EvalResult } from '../types/eval.js';
4
4
  export declare class SqliteAdapter implements IStorageAdapter {
@@ -25,6 +25,11 @@ export declare class SqliteAdapter implements IStorageAdapter {
25
25
  total: number;
26
26
  }>;
27
27
  getDashboardSummary(sinceHours?: number): Promise<DashboardSummary>;
28
+ private periodToSince;
29
+ getEvalStats(period: EvalStatsPeriod): Promise<EvalStats>;
30
+ getEvalStatsTrend(period: EvalStatsPeriod): Promise<EvalStatsTrendBucket[]>;
31
+ getEvalStatsRules(period: EvalStatsPeriod): Promise<EvalStatsRuleBreakdown[]>;
32
+ getEvalStatsFailures(period: EvalStatsPeriod, limit: number): Promise<EvalStatsFailure[]>;
28
33
  deleteTracesOlderThan(days: number): Promise<number>;
29
34
  getDistinctValues(column: string): Promise<string[]>;
30
35
  private rowToTrace;
@@ -167,6 +167,170 @@ export class SqliteAdapter {
167
167
  top_agents: topAgents,
168
168
  };
169
169
  }
170
+ // ---------------------------------------------------------------------------
171
+ // Eval-stats endpoints (v0.2.0 dashboard)
172
+ // ---------------------------------------------------------------------------
173
+ periodToSince(period) {
174
+ const hours = period === '24h' ? 24 : period === '7d' ? 168 : 720;
175
+ return new Date(Date.now() - hours * 60 * 60 * 1000).toISOString();
176
+ }
177
+ async getEvalStats(period) {
178
+ const since = this.periodToSince(period);
179
+ const agg = this.db.prepare(`
180
+ SELECT
181
+ COUNT(*) AS total_evals,
182
+ COALESCE(AVG(score), 0) AS avg_score,
183
+ SUM(CASE WHEN passed = 1 THEN 1 ELSE 0 END) AS passed_count
184
+ FROM eval_results
185
+ WHERE created_at >= ?
186
+ `).get(since);
187
+ const cost = this.db.prepare(`
188
+ SELECT COALESCE(SUM(cost_usd), 0) AS total_cost
189
+ FROM traces
190
+ WHERE timestamp >= ?
191
+ `).get(since);
192
+ const agents = this.db.prepare(`
193
+ SELECT COUNT(DISTINCT agent_name) AS agent_count
194
+ FROM traces
195
+ WHERE timestamp >= ?
196
+ `).get(since);
197
+ // Safety violations — scan rule_results JSON for failing safety rules.
198
+ // rule_results is stored as a JSON array of EvalRuleResult objects.
199
+ const safetyRows = this.db.prepare(`
200
+ SELECT rule_results
201
+ FROM eval_results
202
+ WHERE created_at >= ?
203
+ AND eval_type = 'safety'
204
+ AND passed = 0
205
+ `).all(since);
206
+ const violations = { pii: 0, injection: 0, hallucination: 0 };
207
+ for (const row of safetyRows) {
208
+ const rules = JSON.parse(row.rule_results);
209
+ for (const r of rules) {
210
+ if (r.passed)
211
+ continue;
212
+ if (r.ruleName === 'no_pii')
213
+ violations.pii++;
214
+ if (r.ruleName === 'no_injection_patterns')
215
+ violations.injection++;
216
+ if (r.ruleName === 'no_hallucination_markers')
217
+ violations.hallucination++;
218
+ }
219
+ }
220
+ return {
221
+ passRate: agg.total_evals > 0
222
+ ? Math.round((agg.passed_count / agg.total_evals) * 1000) / 1000
223
+ : 0,
224
+ avgScore: Math.round(agg.avg_score * 1000) / 1000,
225
+ totalEvals: agg.total_evals,
226
+ safetyViolations: violations,
227
+ totalCost: Math.round(cost.total_cost * 100) / 100,
228
+ agentCount: agents.agent_count,
229
+ period,
230
+ };
231
+ }
232
+ async getEvalStatsTrend(period) {
233
+ const since = this.periodToSince(period);
234
+ // Determine bucket format for strftime
235
+ let bucketExpr;
236
+ if (period === '24h') {
237
+ // hourly buckets
238
+ bucketExpr = "strftime('%Y-%m-%dT%H:00:00Z', created_at)";
239
+ }
240
+ else if (period === '7d') {
241
+ // 6-hour buckets: floor hour to nearest 6
242
+ bucketExpr =
243
+ "strftime('%Y-%m-%dT', created_at) || printf('%02d', (CAST(strftime('%H', created_at) AS INTEGER) / 6) * 6) || ':00:00Z'";
244
+ }
245
+ else {
246
+ // daily buckets
247
+ bucketExpr = "strftime('%Y-%m-%dT00:00:00Z', created_at)";
248
+ }
249
+ const rows = this.db.prepare(`
250
+ SELECT
251
+ ${bucketExpr} AS bucket,
252
+ COALESCE(AVG(score), 0) AS avg_score,
253
+ CASE WHEN COUNT(*) > 0
254
+ THEN CAST(SUM(CASE WHEN passed = 1 THEN 1 ELSE 0 END) AS REAL) / COUNT(*)
255
+ ELSE 0 END AS pass_rate,
256
+ COUNT(*) AS eval_count
257
+ FROM eval_results
258
+ WHERE created_at >= ?
259
+ GROUP BY bucket
260
+ ORDER BY bucket
261
+ `).all(since);
262
+ return rows.map((r) => ({
263
+ timestamp: r.bucket,
264
+ avgScore: Math.round(r.avg_score * 1000) / 1000,
265
+ passRate: Math.round(r.pass_rate * 1000) / 1000,
266
+ evalCount: r.eval_count,
267
+ }));
268
+ }
269
+ async getEvalStatsRules(period) {
270
+ const since = this.periodToSince(period);
271
+ const rows = this.db.prepare(`
272
+ SELECT rule_results
273
+ FROM eval_results
274
+ WHERE created_at >= ?
275
+ `).all(since);
276
+ // Aggregate per-rule stats from the JSON arrays
277
+ const ruleMap = new Map();
278
+ for (const row of rows) {
279
+ const rules = JSON.parse(row.rule_results);
280
+ for (const r of rules) {
281
+ const entry = ruleMap.get(r.ruleName) ?? { totalRun: 0, failCount: 0 };
282
+ entry.totalRun++;
283
+ if (!r.passed)
284
+ entry.failCount++;
285
+ ruleMap.set(r.ruleName, entry);
286
+ }
287
+ }
288
+ const result = [];
289
+ for (const [rule, stats] of ruleMap) {
290
+ result.push({
291
+ rule,
292
+ passRate: stats.totalRun > 0
293
+ ? Math.round(((stats.totalRun - stats.failCount) / stats.totalRun) * 1000) / 1000
294
+ : 0,
295
+ totalRun: stats.totalRun,
296
+ failCount: stats.failCount,
297
+ });
298
+ }
299
+ // Sort by passRate ASC (worst rules first)
300
+ result.sort((a, b) => a.passRate - b.passRate);
301
+ return result;
302
+ }
303
+ async getEvalStatsFailures(period, limit) {
304
+ const since = this.periodToSince(period);
305
+ const rows = this.db.prepare(`
306
+ SELECT
307
+ e.trace_id,
308
+ COALESCE(t.agent_name, 'unknown') AS agent_name,
309
+ e.rule_results,
310
+ e.score,
311
+ e.output_text,
312
+ e.created_at
313
+ FROM eval_results e
314
+ LEFT JOIN traces t ON t.trace_id = e.trace_id
315
+ WHERE e.created_at >= ?
316
+ AND e.passed = 0
317
+ ORDER BY e.created_at DESC
318
+ LIMIT ?
319
+ `).all(since, limit);
320
+ return rows.map((r) => {
321
+ // Find the first failing rule to surface as the primary rule
322
+ const rules = JSON.parse(r.rule_results);
323
+ const failingRule = rules.find((rule) => !rule.passed);
324
+ return {
325
+ traceId: r.trace_id ?? '',
326
+ agent: r.agent_name,
327
+ rule: failingRule?.ruleName ?? 'unknown',
328
+ score: Math.round(r.score * 1000) / 1000,
329
+ output: r.output_text.length > 200 ? r.output_text.slice(0, 200) + '...' : r.output_text,
330
+ timestamp: r.created_at,
331
+ };
332
+ });
333
+ }
170
334
  async deleteTracesOlderThan(days) {
171
335
  const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString();
172
336
  const result = this.db.prepare('DELETE FROM traces WHERE timestamp < ?').run(cutoff);
@@ -6,8 +6,15 @@ import { createErrorHandler } from '../middleware/error-handler.js';
6
6
  import { createMcpRateLimiter } from '../middleware/rate-limit.js';
7
7
  export async function createHttpTransport(mcpServer, config, logger) {
8
8
  const app = express();
9
- // Security headers (no CSP — API only, no HTML)
10
- app.use(helmet({ contentSecurityPolicy: false }));
9
+ // Security headers — API-only server, restrictive CSP
10
+ app.use(helmet({
11
+ contentSecurityPolicy: {
12
+ directives: {
13
+ defaultSrc: ["'none'"],
14
+ frameAncestors: ["'none'"],
15
+ },
16
+ },
17
+ }));
11
18
  // Body parser with size limit
12
19
  app.use(express.json({ limit: config.security.requestSizeLimit }));
13
20
  // Health endpoint (no auth, no rate limit)
@@ -1,4 +1,4 @@
1
1
  export type { SpanKind, SpanStatus, SpanEvent, ToolCallRecord, TokenUsage, Span, Trace, } from './trace.js';
2
2
  export type { EvalType, EvalRule, EvalContext, EvalRuleResult, EvalResult, CustomRuleType, CustomRuleDefinition, } from './eval.js';
3
- export type { TraceFilter, TraceQueryOptions, TraceQueryResult, DashboardSummary, IStorageAdapter, } from './query.js';
3
+ export type { TraceFilter, TraceQueryOptions, TraceQueryResult, DashboardSummary, EvalStatsPeriod, EvalStats, EvalStatsTrendBucket, EvalStatsRuleBreakdown, EvalStatsFailure, IStorageAdapter, } from './query.js';
4
4
  export type { IrisConfig } from './config.js';
@@ -22,6 +22,40 @@ export interface TraceQueryResult {
22
22
  limit: number;
23
23
  offset: number;
24
24
  }
25
+ export type EvalStatsPeriod = '24h' | '7d' | '30d';
26
+ export interface EvalStats {
27
+ passRate: number;
28
+ avgScore: number;
29
+ totalEvals: number;
30
+ safetyViolations: {
31
+ pii: number;
32
+ injection: number;
33
+ hallucination: number;
34
+ };
35
+ totalCost: number;
36
+ agentCount: number;
37
+ period: EvalStatsPeriod;
38
+ }
39
+ export interface EvalStatsTrendBucket {
40
+ timestamp: string;
41
+ avgScore: number;
42
+ passRate: number;
43
+ evalCount: number;
44
+ }
45
+ export interface EvalStatsRuleBreakdown {
46
+ rule: string;
47
+ passRate: number;
48
+ totalRun: number;
49
+ failCount: number;
50
+ }
51
+ export interface EvalStatsFailure {
52
+ traceId: string;
53
+ agent: string;
54
+ rule: string;
55
+ score: number;
56
+ output: string;
57
+ timestamp: string;
58
+ }
25
59
  export interface DashboardSummary {
26
60
  total_traces: number;
27
61
  avg_latency_ms: number;
@@ -61,4 +95,8 @@ export interface IStorageAdapter {
61
95
  getDashboardSummary(sinceHours?: number): Promise<DashboardSummary>;
62
96
  deleteTracesOlderThan(days: number): Promise<number>;
63
97
  getDistinctValues(column: string): Promise<string[]>;
98
+ getEvalStats(period: EvalStatsPeriod): Promise<EvalStats>;
99
+ getEvalStatsTrend(period: EvalStatsPeriod): Promise<EvalStatsTrendBucket[]>;
100
+ getEvalStatsRules(period: EvalStatsPeriod): Promise<EvalStatsRuleBreakdown[]>;
101
+ getEvalStatsFailures(period: EvalStatsPeriod, limit: number): Promise<EvalStatsFailure[]>;
64
102
  }
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@iris-eval/mcp-server",
3
- "version": "0.1.2",
4
- "description": "MCP-native agent evaluation and observability server",
3
+ "version": "0.1.4",
4
+ "description": "The agent eval standard for MCP — score output quality, catch safety failures, enforce cost budgets",
5
+ "mcpName": "io.github.iris-eval/mcp-server",
5
6
  "type": "module",
6
7
  "main": "dist/index.js",
7
8
  "types": "dist/index.d.ts",
@@ -20,17 +21,31 @@
20
21
  "test:watch": "vitest",
21
22
  "test:coverage": "vitest run --coverage",
22
23
  "test:integration": "vitest run tests/integration/",
24
+ "version:check": "bash scripts/check-version.sh",
25
+ "version:sync": "node scripts/sync-versions.mjs",
23
26
  "clean": "rm -rf dist coverage",
24
27
  "seed:demo": "tsx scripts/seed-demo-data.ts",
25
- "demo": "tsx scripts/demo.ts"
28
+ "demo": "tsx scripts/demo.ts",
29
+ "postinstall": "echo \"\\n ✅ Iris installed — the agent eval standard for MCP\\n 📖 Docs: https://iris-eval.com\\n 🎯 Try the playground: https://iris-eval.com/playground\\n ⭐ Star us: https://github.com/iris-eval/mcp-server\\n\""
26
30
  },
27
31
  "keywords": [
28
32
  "mcp",
33
+ "mcp-server",
34
+ "model-context-protocol",
29
35
  "agent",
36
+ "ai-agent",
30
37
  "evaluation",
31
38
  "observability",
32
39
  "tracing",
33
- "llm"
40
+ "llm",
41
+ "claude",
42
+ "agent-evaluation",
43
+ "ai-observability",
44
+ "pii-detection",
45
+ "cost-tracking",
46
+ "agent-eval",
47
+ "output-quality",
48
+ "quality-gate"
34
49
  ],
35
50
  "author": "",
36
51
  "license": "MIT",
@@ -38,7 +53,7 @@
38
53
  "type": "git",
39
54
  "url": "git+https://github.com/iris-eval/mcp-server.git"
40
55
  },
41
- "homepage": "https://github.com/iris-eval/mcp-server#readme",
56
+ "homepage": "https://iris-eval.com",
42
57
  "bugs": {
43
58
  "url": "https://github.com/iris-eval/mcp-server/issues"
44
59
  },
@@ -53,7 +68,7 @@
53
68
  },
54
69
  "dependencies": {
55
70
  "@modelcontextprotocol/sdk": "^1.27.0",
56
- "better-sqlite3": "^11.0.0",
71
+ "better-sqlite3": "^12.8.0",
57
72
  "express": "^5.1.0",
58
73
  "express-rate-limit": "^8.3.1",
59
74
  "helmet": "^8.1.0",
@@ -65,7 +80,7 @@
65
80
  "@types/better-sqlite3": "^7.6.0",
66
81
  "@types/express": "^5.0.0",
67
82
  "@types/node": "^22.0.0",
68
- "@typescript-eslint/eslint-plugin": "^8.57.0",
83
+ "@typescript-eslint/eslint-plugin": "^8.57.1",
69
84
  "@typescript-eslint/parser": "^8.57.0",
70
85
  "@vitest/coverage-v8": "^3.0.0",
71
86
  "eslint": "^9.0.0",
package/server.json CHANGED
@@ -1,69 +1,43 @@
1
1
  {
2
- "name": "iris-eval",
3
- "version": "0.1.0",
4
- "description": "MCP-native agent evaluation and observability server",
5
- "homepage": "https://github.com/iris-eval/mcp-server",
6
- "packages": {
7
- "npm": {
8
- "name": "@iris-eval/mcp-server",
9
- "registry": "https://registry.npmjs.org"
10
- },
11
- "oci": {
12
- "name": "ghcr.io/iris-eval/mcp-server",
13
- "registry": "ghcr.io"
14
- }
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
+ "name": "io.github.iris-eval/mcp-server",
4
+ "description": "MCP-native agent evaluation and observability server for AI agents",
5
+ "repository": {
6
+ "url": "https://github.com/iris-eval/mcp-server",
7
+ "source": "github"
15
8
  },
16
- "tools": [
17
- {
18
- "name": "log_trace",
19
- "description": "Log an agent execution trace with spans, tool calls, and metrics"
20
- },
9
+ "version": "0.1.4",
10
+ "packages": [
21
11
  {
22
- "name": "evaluate_output",
23
- "description": "Evaluate agent output quality using configurable rules"
24
- },
25
- {
26
- "name": "get_traces",
27
- "description": "Query stored traces with filters, pagination, and summary stats"
28
- }
29
- ],
30
- "resources": [
31
- {
32
- "uri": "iris://dashboard/summary",
33
- "description": "Dashboard summary with key metrics and trends"
34
- },
35
- {
36
- "uri_template": "iris://traces/{trace_id}",
37
- "description": "Full trace detail with spans and evaluation results"
38
- }
39
- ],
40
- "env": {
41
- "IRIS_TRANSPORT": {
42
- "description": "Transport type: stdio or http",
43
- "default": "stdio"
44
- },
45
- "IRIS_PORT": {
46
- "description": "HTTP transport port",
47
- "default": "3000"
48
- },
49
- "IRIS_DB_PATH": {
50
- "description": "SQLite database path",
51
- "default": "~/.iris/iris.db"
52
- },
53
- "IRIS_LOG_LEVEL": {
54
- "description": "Log level: debug, info, warn, error",
55
- "default": "info"
56
- },
57
- "IRIS_DASHBOARD": {
58
- "description": "Enable web dashboard",
59
- "default": "false"
60
- },
61
- "IRIS_API_KEY": {
62
- "description": "API key for HTTP authentication (optional, recommended for production)"
63
- },
64
- "IRIS_ALLOWED_ORIGINS": {
65
- "description": "Comma-separated list of allowed CORS origins",
66
- "default": "http://localhost:*"
12
+ "registryType": "npm",
13
+ "identifier": "@iris-eval/mcp-server",
14
+ "version": "0.1.3",
15
+ "transport": {
16
+ "type": "stdio"
17
+ },
18
+ "environmentVariables": [
19
+ {
20
+ "description": "API key for HTTP authentication (optional, recommended for production)",
21
+ "isRequired": false,
22
+ "format": "string",
23
+ "isSecret": true,
24
+ "name": "IRIS_API_KEY"
25
+ },
26
+ {
27
+ "description": "SQLite database path",
28
+ "isRequired": false,
29
+ "format": "string",
30
+ "isSecret": false,
31
+ "name": "IRIS_DB_PATH"
32
+ },
33
+ {
34
+ "description": "Log level: debug, info, warn, error",
35
+ "isRequired": false,
36
+ "format": "string",
37
+ "isSecret": false,
38
+ "name": "IRIS_LOG_LEVEL"
39
+ }
40
+ ]
67
41
  }
68
- }
42
+ ]
69
43
  }