Skip to main content
Glama
iris-eval

iris-eval/mcp-server

by iris-eval

Verify Citations

verify_citations

Verify each citation in agent output by fetching sources and using an LLM judge to confirm support, providing per-citation verdicts and an overall support ratio.

Instructions

Extract citations from agent output, fetch the cited sources, and use an LLM judge to check whether each source supports the claim in context. Returns per-citation verdicts + an overall support ratio.

Sibling tools — evaluate_with_llm_judge runs general semantic scoring (accuracy, helpfulness, correctness, faithfulness); this tool is specifically for citation grounding (does the cited source actually support the claim). evaluate_output's no_hallucination_markers heuristic detects FABRICATED-looking citations cheaply (free, no fetch); this tool resolves and verifies them (paid, opt-in fetch, SSRF-guarded). log_trace / get_traces handle trace I/O. verify_citations is the GROUNDING-CHECK path — narrowest in scope, deepest in rigor.

Behavior. Three-phase pipeline: (1) regex extraction of [N] numbered refs, (Author, Year) parentheticals, bare URLs, and DOIs (in-process, no network); (2) SSRF-guarded fetch of URL + DOI citations, with scheme allowlist, private/link-local/cloud-metadata IP blocking, optional domain allowlist (IRIS_CITATION_DOMAINS), 10s timeout, 5MB body cap, manual redirect chase (max 3, re-checked), in-process LRU cache; (3) per-citation LLM judge call asking "does this source support this claim?" with a 256-token verdict. Opt-in via allow_fetch=true or IRIS_CITATION_ALLOW_FETCH=1 — Iris refuses outbound HTTP by default. Cost-capped across the entire call by max_cost_usd_total (default $1.00) — the pipeline stops when the cap would be exceeded. Rate-limited to 20 req/min on HTTP MCP. Writes one eval_result row tagged with per-citation provenance.

Output shape. Returns JSON: { "id": "<uuid>", "overall_score": 0..1|null, "passed": boolean, "total_citations_found": number, "total_resolved": number, "total_supported": number, "total_cost_usd": number, "citations": [{ "citation": { "raw", "kind", "identifier", "offset_start", "offset_end" }, "resolve_status": "ok"|"skipped"|"error", "resolve_error"?, "source"?: { "url", "status", "content_type", "bytes_fetched", "truncated" }, "judge"?: { "supported", "confidence", "rationale", "cost_usd", "latency_ms", "input_tokens", "output_tokens" } }] }. overall_score = supported / resolved; null when nothing resolvable was found.

Use when the output makes factual claims backed by [1]-style references, DOIs, or URLs and you want to separate "cited correctly" from "cited and wrong" from "cited but unresolvable". Particularly useful for research/legal/medical agents where fabricated citations are the dominant failure mode.

Don't use when the agent output has no citations at all (overall_score will be null; the tool degrades gracefully but a heuristic rule is cheaper). Don't use without allow_fetch=true or IRIS_CITATION_ALLOW_FETCH=1 — the tool refuses outbound HTTP unless explicitly enabled. Don't use with an open allowlist + untrusted output on the public internet; you are effectively running a user-directed fetcher. For stricter safety set IRIS_CITATION_DOMAINS to a curated list.

Parameters. model is required; provider auto-detected from model name (override only for ambiguous IDs). allow_fetch=false by default — outbound HTTP is REFUSED unless explicitly true OR IRIS_CITATION_ALLOW_FETCH=1 env. domain_allowlist suffix-matches hostnames (e.g., "wikipedia.org" allows en.wikipedia.org); merged with IRIS_CITATION_DOMAINS env (UNION — either source permits). max_citations defaults 20, hard cap 50 (extras are skipped silently, NOT errored — check total_citations_found in the response if precise). max_cost_usd_total defaults $1.00 — the pipeline stops mid-citation when the next judge call would exceed the cap (returns partial verdicts). per_source_timeout_ms defaults 10000 (10s); per_source_max_bytes defaults 5MB (truncates at boundary, judges still run on truncated content). trace_id optional but recommended. Defaults: max_citations=20, max_cost_usd_total=$1.00, per_source_timeout_ms=10000, per_source_max_bytes=5242880, allow_fetch=false.

Error modes. Throws when the API key env var is missing. Throws "Unknown model" on unsupported model IDs. Per-citation errors are collected (resolve_error.kind = bad_scheme / ssrf / not_allowed_domain / timeout / too_large / bad_status / redirect_loop / not_text / fetch_disabled / malformed_judge_response / cost_cap_reached / unresolvable_kind) and returned in the response rather than thrown. An empty output or output with zero extractable citations returns overall_score=null + passed=true (nothing to fail).

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
modelYesJudge model for per-citation verification. Supported: anthropic = claude-opus-4-7 | claude-sonnet-4-6 | claude-haiku-4-5-20251001; openai = gpt-4o | gpt-4o-mini | o1-mini.
outputYesThe agent output containing citations to verify
providerNoAuto-detected from model when omitted
trace_idNoLink verification result to a trace
allow_fetchNoPermit outbound HTTP to resolve URLs/DOIs. Defaults to IRIS_CITATION_ALLOW_FETCH=1; false otherwise. SSRF-guarded regardless.
max_citationsNoMax citations to verify (extras skipped); default 20
domain_allowlistNoRestrict fetches to hostnames in this list (suffix match allowed). Merged with IRIS_CITATION_DOMAINS env.
max_cost_usd_totalNoCap TOTAL judge cost across all citations in this call; default $1.00
per_source_max_bytesNoPer-URL body cap; default 5MB
per_source_timeout_msNoPer-URL fetch timeout; default 10_000
Install Server

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations are minimal (readOnlyHint=false, openWorldHint=true), leaving the description to carry nearly all behavioral context—and it does. It discloses SSRF-guarded fetch mechanics (scheme allowlist, IP blocking, redirect chase with re-checks), default refusal of outbound HTTP unless allow_fetch=true or IRIS_CITATION_ALLOW_FETCH=1, cost caps that stop the pipeline mid-citation, 20 req/min MCP rate limit, and that it writes one eval_result row. These details align with and enrich the open-world hint without contradicting any annotation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but front-loaded and ruthlessly organized: opening summary, then labeled sections for Sibling tools, Behavior, Output shape, Use when, Don't use, Parameters, and Error modes. Each sentence carries distinct operational facts with no filler; the length is proportionate to the tool's 10-parameter, network-facing, judge-calling complexity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema present, the description supplies a complete JSON response shape, covering every field. It also documents all throw-vs-collect error semantics, per-citation error kinds, graceful degradation (null overall_score), and safety/cost/time limits. For a tool of this complexity, everything needed for correct invocation and interpretation is present.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Although the schema already covers 100% of parameters with descriptions, the tool description adds substantial operational meaning: defaults for every parameter, the iri_citation_allow_fetch env-var interaction, suffix-matching for domain_allowlist with union merge over IRIS_CITATION_DOMAINS, silent skip of citations beyond max_citations (hard cap 50), mid-call cost-cap behavior, and the full resolve_error.kind taxonomy. This goes well beyond the structured schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific three-phase verb chain ('Extract citations from agent output, fetch the cited sources, and use an LLM judge to check...') and names the exact return value (per-citation verdicts + overall support ratio). It then explicitly distinguishes from siblings evaluate_with_llm_judge (general semantic scoring) and evaluate_output (cheap fabricated-citation heuristic), making the tool's unique scope unmistakable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The 'Use when' paragraph gives concrete preconditions (factual claims with [1]-style references, DOIs, or URLs; research/legal/medical domains). The 'Don't use' paragraph lists three explicit exclusions (no citations, no allow_fetch, open allowlist with untrusted output). Alternatives are named directly: evaluate_with_llm_judge for generic scoring, evaluate_output for cheap detection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/iris-eval/mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server