Claim Support Check
verify_claimVerify a factual claim against provided public evidence URLs using keyword matching. Input claim, URLs, and keywords; each source is marked supporting when at least half the keywords appear. Use for evidence-backed checks on known pages.
Instructions
Check whether a factual claim is supported by a specific set of public evidence URLs that you already have. For each source, the tool performs a case-insensitive keyword match over the fetched page body, then marks that source as supporting the claim when at least half of the supplied keywords appear. Use this for evidence-backed claim checks on known pages, not for open-ended search or semantic fact checking. Registry responses are cached for 5 minutes.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| claim | Yes | Plain-language claim to verify, for example 'AWS Business support includes 24/7 phone support'. | |
| evidence_urls | Yes | One to ten public documentation, pricing, policy, or support URLs that are likely to contain direct evidence for the claim. | |
| keywords | Yes | Keywords or short phrases that should appear on supporting pages. Matching is case-insensitive substring matching. |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| claim | Yes | Claim that was evaluated. | |
| sources | Yes | Per-source evidence results. | |
| verdict | Yes | Aggregate verdict across all supplied sources. |
Implementation Reference
- src/index.ts:975-1094 (registration)Registration of the 'verify_claim' tool via this.server.registerTool(), including its input/output schema definitions and the handler function.
this.server.registerTool( "verify_claim", { title: "Claim Support Check", description: "Check whether a factual claim is supported by a specific set of public " + "evidence URLs that you already have. For each source, the tool performs a " + "case-insensitive keyword match over the fetched page body, then marks that " + "source as supporting the claim when at least half of the supplied keywords " + "appear. Use this for evidence-backed claim checks on known pages, not for " + "open-ended search, semantic reasoning, or contradiction extraction. The " + "aggregate verdict is driven only by the per-page keyword support ratio. " + "Fetched pages are cached for 5 minutes.", inputSchema: { claim: z.string().trim().min(5).describe( "Plain-language claim to verify, for example 'AWS Business support includes 24/7 phone support'.", ), evidence_urls: z.array(z.string().url()).min(1).max(10).describe( "One to ten public documentation, pricing, policy, or support URLs that are likely to contain direct evidence for the claim.", ), keywords: z.array(z.string().trim().min(1)).min(1).max(20).describe( "Keywords or short phrases that should appear on supporting pages. Matching is case-insensitive substring matching, so choose phrases that are likely to appear verbatim.", ), }, outputSchema: { claim: z.string().describe( "Claim that was evaluated.", ), sources: z.array(z.object({ url: z.string().describe( "Evidence URL that was checked.", ), accessible: z.boolean().describe( "True when the evidence page could be fetched.", ), cached: z.boolean().describe( "True when the page body came from the 5-minute cache.", ).optional(), keywordsMatched: z.array(z.string()).describe( "Subset of supplied keywords that were found on the page.", ).optional(), keywordsTotal: z.number().int().nonnegative().describe( "Total number of keywords the tool looked for on this page.", ).optional(), matchRatio: z.number().min(0).max(1).describe( "Matched-keyword ratio for this source, from 0 to 1.", ).optional(), supports: z.boolean().describe( "True when the page met the current support threshold of at least half of the supplied keywords.", ), error: z.string().describe( "Fetch error when the evidence page could not be checked.", ).optional(), })).describe( "Per-source evidence results.", ), verdict: z.object({ supporting: z.number().int().nonnegative().describe( "Number of sources marked as supporting the claim.", ), contradicting: z.number().int().nonnegative().describe( "Number of sources not marked as supporting the claim.", ), total: z.number().int().nonnegative().describe( "Total number of evidence sources checked.", ), confidence: z.number().min(0).max(1).describe( "Share of sources that supported the claim.", ), summary: z.enum(["CONFIRMED", "UNCONFIRMED", "LIKELY TRUE", "LIKELY FALSE"]).describe( "High-level verdict derived from the supporting-source ratio: all sources supporting => CONFIRMED, none => UNCONFIRMED, majority => LIKELY TRUE, otherwise LIKELY FALSE.", ), }).describe( "Aggregate verdict across all supplied sources.", ), }, annotations: readOnlyNetworkToolAnnotations, }, async ({ claim, evidence_urls, keywords }) => { const sources = []; for (const url of evidence_urls) { try { const { body, fromCache } = await cachedFetch(sql, url); const bodyLower = body.toLowerCase(); const keywordHits = keywords.filter(kw => bodyLower.includes(kw.toLowerCase())); sources.push({ url, accessible: true, cached: fromCache, keywordsMatched: keywordHits, keywordsTotal: keywords.length, matchRatio: +(keywordHits.length / keywords.length).toFixed(2), supports: keywordHits.length >= keywords.length * 0.5, }); } catch (e: unknown) { sources.push({ url, accessible: false, error: e instanceof Error ? e.message : String(e), supports: false, }); } } const supporting = sources.filter(s => s.supports).length; logUsage("verify_claim", true); return structuredToolResult({ claim, sources, verdict: { supporting, contradicting: sources.length - supporting, total: sources.length, confidence: +(supporting / sources.length).toFixed(2), summary: supporting === sources.length ? "CONFIRMED" : supporting === 0 ? "UNCONFIRMED" : supporting >= sources.length * 0.5 ? "LIKELY TRUE" : "LIKELY FALSE", }, }); } ); - src/index.ts:1053-1094 (handler)Handler function for 'verify_claim' that fetches each evidence URL, performs case-insensitive substring matching of keywords against the page body, marks a source as supporting if at least half of keywords match, and produces an aggregate verdict (CONFIRMED, UNCONFIRMED, LIKELY TRUE, LIKELY FALSE).
async ({ claim, evidence_urls, keywords }) => { const sources = []; for (const url of evidence_urls) { try { const { body, fromCache } = await cachedFetch(sql, url); const bodyLower = body.toLowerCase(); const keywordHits = keywords.filter(kw => bodyLower.includes(kw.toLowerCase())); sources.push({ url, accessible: true, cached: fromCache, keywordsMatched: keywordHits, keywordsTotal: keywords.length, matchRatio: +(keywordHits.length / keywords.length).toFixed(2), supports: keywordHits.length >= keywords.length * 0.5, }); } catch (e: unknown) { sources.push({ url, accessible: false, error: e instanceof Error ? e.message : String(e), supports: false, }); } } const supporting = sources.filter(s => s.supports).length; logUsage("verify_claim", true); return structuredToolResult({ claim, sources, verdict: { supporting, contradicting: sources.length - supporting, total: sources.length, confidence: +(supporting / sources.length).toFixed(2), summary: supporting === sources.length ? "CONFIRMED" : supporting === 0 ? "UNCONFIRMED" : supporting >= sources.length * 0.5 ? "LIKELY TRUE" : "LIKELY FALSE", }, }); } ); - src/index.ts:977-1051 (schema)Input/output schema definitions for 'verify_claim': takes a claim, evidence_urls (1-10 URLs), and keywords (1-20 phrases); returns per-source match results and an aggregate verdict.
{ title: "Claim Support Check", description: "Check whether a factual claim is supported by a specific set of public " + "evidence URLs that you already have. For each source, the tool performs a " + "case-insensitive keyword match over the fetched page body, then marks that " + "source as supporting the claim when at least half of the supplied keywords " + "appear. Use this for evidence-backed claim checks on known pages, not for " + "open-ended search, semantic reasoning, or contradiction extraction. The " + "aggregate verdict is driven only by the per-page keyword support ratio. " + "Fetched pages are cached for 5 minutes.", inputSchema: { claim: z.string().trim().min(5).describe( "Plain-language claim to verify, for example 'AWS Business support includes 24/7 phone support'.", ), evidence_urls: z.array(z.string().url()).min(1).max(10).describe( "One to ten public documentation, pricing, policy, or support URLs that are likely to contain direct evidence for the claim.", ), keywords: z.array(z.string().trim().min(1)).min(1).max(20).describe( "Keywords or short phrases that should appear on supporting pages. Matching is case-insensitive substring matching, so choose phrases that are likely to appear verbatim.", ), }, outputSchema: { claim: z.string().describe( "Claim that was evaluated.", ), sources: z.array(z.object({ url: z.string().describe( "Evidence URL that was checked.", ), accessible: z.boolean().describe( "True when the evidence page could be fetched.", ), cached: z.boolean().describe( "True when the page body came from the 5-minute cache.", ).optional(), keywordsMatched: z.array(z.string()).describe( "Subset of supplied keywords that were found on the page.", ).optional(), keywordsTotal: z.number().int().nonnegative().describe( "Total number of keywords the tool looked for on this page.", ).optional(), matchRatio: z.number().min(0).max(1).describe( "Matched-keyword ratio for this source, from 0 to 1.", ).optional(), supports: z.boolean().describe( "True when the page met the current support threshold of at least half of the supplied keywords.", ), error: z.string().describe( "Fetch error when the evidence page could not be checked.", ).optional(), })).describe( "Per-source evidence results.", ), verdict: z.object({ supporting: z.number().int().nonnegative().describe( "Number of sources marked as supporting the claim.", ), contradicting: z.number().int().nonnegative().describe( "Number of sources not marked as supporting the claim.", ), total: z.number().int().nonnegative().describe( "Total number of evidence sources checked.", ), confidence: z.number().min(0).max(1).describe( "Share of sources that supported the claim.", ), summary: z.enum(["CONFIRMED", "UNCONFIRMED", "LIKELY TRUE", "LIKELY FALSE"]).describe( "High-level verdict derived from the supporting-source ratio: all sources supporting => CONFIRMED, none => UNCONFIRMED, majority => LIKELY TRUE, otherwise LIKELY FALSE.", ), }).describe( "Aggregate verdict across all supplied sources.", ), }, annotations: readOnlyNetworkToolAnnotations,