Skip to main content
Glama

honesty-mcp

Try the kits in your browser → · Part of honesty kits, a family of small checks for the claims an AI product makes.

An MCP (Model Context Protocol) server that exposes eleven already-built, zero-runtime-dependency "honesty SDK" TypeScript libraries as tools any MCP-compatible coding agent (Claude Code, Claude Desktop, or any other MCP client) can call while building or auditing a product — grounded-citation checking, evidence corroboration grading, payout/mutation-invariance checks (scenario-tested, not a formal proof for every possible input), trust/ authenticity scoring, provenance-claim validation, a claims registry, a tamper-evident audit chain, and recommendation/decision grading plus engine-vs-human divergence, plus scaffolding for two runtime-library kits that don't fit the "check this content" shape.

This server is thin by design: every tool is a Zod input schema plus a handler that imports and calls the real, unmodified export from the wrapped kit. It does not reimplement any of the underlying logic.

Quickstart

claude mcp add honesty-mcp -- npx -y honesty-mcp

Then ask your coding agent to run check_grounding on a draft answer and its sources. Each sentence comes back as grounded, placeholder, ungrounded or invalid (a citation whose source is missing from the evidence). It checks structure only: it does not decide whether a source is true.

Thirteen tools are listed by default. The three paths that run JavaScript the agent sends are off unless you set HONESTY_MCP_ENABLE_CODE_EXEC=1; read A note on the code-execution tools first.

Related MCP server: Agent Trust Stack MCP Server

Install

honesty-mcp is published on npm and wraps its eleven sibling "honesty SDK" kits as ordinary registry dependencies (semver ranges, not local file: paths) — npm install (or a plain npx) resolves everything from the public registry, with nothing else to check out first.

The fastest way to run it, with no install step at all:

npx honesty-mcp

Or add it to a project:

npm install honesty-mcp

Adding it to an MCP client

Claude Code:

claude mcp add honesty-mcp -- npx -y honesty-mcp

Any other MCP client that reads an mcpServers config (Claude Desktop's claude_desktop_config.json uses the same shape):

{
  "mcpServers": {
    "honesty-mcp": {
      "command": "npx",
      "args": ["-y", "honesty-mcp"]
    }
  }
}

Three of the tools run JavaScript that the calling agent sends, so they are off by default. To use them, add the environment variable HONESTY_MCP_ENABLE_CODE_EXEC=1 to the server's environment (see A note on the code-execution tools first):

claude mcp add -e HONESTY_MCP_ENABLE_CODE_EXEC=1 honesty-mcp -- npx -y honesty-mcp
{
  "mcpServers": {
    "honesty-mcp": {
      "command": "npx",
      "args": ["-y", "honesty-mcp"],
      "env": { "HONESTY_MCP_ENABLE_CODE_EXEC": "1" }
    }
  }
}

The server runs on the stdio transport — it reads JSON-RPC requests from stdin and writes responses to stdout, logging only a one-line startup banner to stderr so stdout stays a clean JSON-RPC channel. This is the transport Claude Code, Claude Desktop, and most local/CLI MCP client integrations expect for a locally-run server; it is not an HTTP server and has no port to browse to.

Listing in the MCP registry

honesty-mcp also ships a server.json (validated against the official schema) so it can be listed on the official MCP registry, under the name io.github.lkopietz3-byte/honesty-mcp. Listing is a manual, one-time step the maintainer runs after this package is on npm — it is not run as part of this repo's CI or npm publish. Exact commands, from the registry's own docs (publishing guide, CLI reference):

# 1. Install the publisher CLI (macOS/Linux)
curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher
sudo mv mcp-publisher /usr/local/bin/

# 2. Log in with GitHub (proves ownership of the io.github.lkopietz3-byte namespace)
mcp-publisher login github

# 3. Publish (validates server.json against the schema, then submits it)
mcp-publisher publish

package.json's mcpName field (io.github.lkopietz3-byte/honesty-mcp) must match server.json's name field exactly — that's how the registry verifies the npm package and the registry listing belong to the same publisher (see package-types.mdx, "Ownership Verification").

Tools

9 content-checking kits, 12 tools (kits 1–9: hand one of these real content or data, get back a structured verdict):

Tool

Wraps

One-line purpose

check_grounding

grounding-kit

Checks citation structure in AI-generated text, sentence by sentence: uncited claims, honest placeholders, and citations whose marker is missing or whose evidence doesn't match lexically. Structural only; it does not verify that the evidence is true. The word-overlap matcher rejects some faithful paraphrases and accepts a wrong figure or a negated claim when most words overlap, so read invalid as "send to a person".

corroborate_evidence

corroboration-kit

Reports the evidence direction (supports / contradicts / mixed / none) and a graded verdict from distinct sources, not a vote count. With corroboration-kit 0.3 and later, sources count by independent origin (pages of one site count once unless you declare an origin). Independence is not verified, and confirmed can mean confirmed-contradicted, so read the direction first.

check_payout_invariance

payout-invariance-kit

Checks, for the scenarios you supply, whether a ranking engine's output changes with who pays more (runtime mode, off unless HONESTY_MCP_ENABLE_CODE_EXEC=1) or whether payout identifiers appear in source text you send (static-imports mode, always available; it never reads files from disk). Static matching is whole-word: commission does not match commissionRate, so list full names or, with payout-invariance-kit 0.3 and later, pass matchIdentifierParts: true. Not a formal proof for every possible payout configuration.

check_mutation_invariance

mutation-invariance-kit

Off unless HONESTY_MCP_ENABLE_CODE_EXEC=1 (it is not listed otherwise). Checks, for the scenarios you supply, whether a decision/score/ranking function's output depends on a variable it claims not to (protected attribute, geography, price, or anything you name). Not a formal proof for every possible input.

score_trust_identified

trust-core (identified)

Scores an entity from known, identified contributors (reviewer accounts, raters, inspectors), shrinking thin evidence toward a prior. With no weighted evidence it returns the prior with insufficient confidence, not a measured score.

assess_anonymous_authenticity

trust-core (anonymous)

Scores unattributed/scraped sentiment on how organic it looks, with a heuristic discount for two specific patterns (source concentration, unusually uniform sentiment). It does not detect fabrication or verify independence, it is not a sentiment ranking (a strongly negative corpus scores lower than a positive one), and it reports no score (trustScore: null) when no signal carries weight.

check_provenance_claims

provenance-kit

Flags certainty-implying language ("(verified)", "guaranteed") not backed by an appropriate provenance tier. The default phrase list is short (eleven phrases) and phrases match as word prefixes.

check_claims_registry

claims-registry-kit

Buckets public-facing claims as current / stale / unverified against their linked evidence and last-verified date. With claims-registry-kit 0.4 and later, a placeholder reference such as TODO is unverified and the age limit is exact to the millisecond.

append_audit_entry

audit-chain-kit

Appends one entry to a hash-chained, tamper-evident audit log.

verify_audit_chain

audit-chain-kit

Independently re-verifies a hash chain from genesis (an empty chain is valid with nothing checked); detects mutation and severed links unconditionally, plain tail deletion with expectedMinLength, and truncate-and-re-append (or a full rewrite) only with anchor; expectedMinLength alone does NOT catch a truncate-and-re-append.

grade_decision

advice-ledger-kit

Grades one recommendation-and-decision pair against a before/after observation log, exposure-aligned, with separate floors per window and machine-readable refusal codes. holding requires both the exposed bad count to stay under refuteThreshold AND its bad rate to be below the baseline's (exact comparison, not the rounded badRate; with advice-ledger-kit 0.2 an equal rate also held); either failing is not-holding. The refute bar is a fixed count, not a rate (see the tool description).

compute_divergence

advice-ledger-kit

Measures how often an engine and a human disagreed, and where a later outcome exists, reports engine-right/human-right as separate, never-blended counts. The optional custom groupBySource input is off unless HONESTY_MCP_ENABLE_CODE_EXEC=1.

2 scaffolding tools (agent-receipt-kit, cost-governor-kit — these are runtime libraries a project installs and imports into its own running code, not something checked on-demand the same way; see the code comments in src/tools/agentReceiptScaffold.ts / costGovernorScaffold.ts for why a "check this content" shape would misrepresent them):

Tool

Wraps

One-line purpose

scaffold_agent_receipts

agent-receipt-kit

Explains the issue-a-packet / verify-the-claim authorization pattern for AI agents, with an install step, a starter snippet, and (optionally) a live accepted/rejected worked example run against the real kit.

scaffold_cost_governor

cost-governor-kit

Explains the estimated pre-call spend check + cache-aware pricing math (default 0.1x cache-read rate, overridable per model via cacheReadPerMillion) + advisory (not concurrency-safe) check-then-commit usage-counting pattern (a commit failure after a successful call returns commitError instead of discarding the result), with an install step, a starter snippet, and (optionally) a live worked example.

That's 9 kits, 12 content-checking tool slots (payout-invariance-kit, audit-chain-kit, and advice-ledger-kit each got 2 tools instead of 1, since each bundles two genuinely distinct operations — runtime check vs. static grep; append vs. verify; grading one decision vs. measuring divergence across a whole population — that read better as separate, single-purpose MCP tools than as one tool with a mode switch) plus 2 scaffolding tools = 14 tools total.

That is 14 tools when code execution is enabled. With it off (the default), check_mutation_invariance is not listed, so a client sees 13.

A note on the code-execution tools

These tools are off by default. check_payout_invariance (runtime mode) and check_mutation_invariance wrap kit functions whose real signature takes an actual JavaScript function (a ranking function, a mutation closure); there is no way to represent a function as MCP JSON arguments. Both tools accept that function as a source-code string and build the real function via the Function constructor, inside the worker that src/lib/runFunctionJob.ts starts after the code-execution switch check, before calling the unmodified kit export with it. (src/lib/buildFunction.ts is the same builder kept as an independently tested reference copy; nothing calls it at runtime.) compute_divergence's optional config.groupBySource uses the same mechanism for advice-ledger-kit's groupBy config function, but only when a caller actually supplies it, and omitting it (the common case) needs no code execution at all, since the library's own default groups by each pair's group field. This is equivalent to eval for that one string.

Because an agent that has been fed hostile text could be talked into sending code, the server only offers these paths when the operator turns them on by setting HONESTY_MCP_ENABLE_CODE_EXEC=1 in the server's environment. Exactly 1 enables them; any other value (true, yes, 0, empty) leaves them off. While they are off:

  • check_mutation_invariance is not registered, so it does not appear in the tool list.

  • check_payout_invariance is listed with static-imports mode only.

  • compute_divergence is listed without the groupBySource input, and sending it is rejected.

  • The server's initialize result carries a short note naming the variable.

  • runFunctionJob (src/lib/runFunctionJob.ts), the one place caller JavaScript is ever run, refuses to start a worker. Its error names HONESTY_MCP_ENABLE_CODE_EXEC.

Every other tool is unchanged. The default is one named constant, CODE_EXEC_ENABLED_BY_DEFAULT in src/lib/codeExec.ts.

Turning it on does not isolate anything. The code still runs with this process's full filesystem, network and environment access. It is the same trust model as the agent running node -e or vitest run itself, and it is not designed to be exposed to untrusted, remote, or adversarial input. Only enable it for a server driven by a trusted local agent, and only pass code you wrote or trust.

Static-imports mode never reads files from disk

check_payout_invariance's static-imports mode takes files as a map of path to file content that the caller sends. A list of paths is rejected with an error. The wrapped kit would read any readable path it was given and return the matching lines, which would let an agent read arbitrary files from the machine one line at a time, so this server does not pass paths through. To scan files, have the agent read them and send the text.

All three of these run inside a worker_threads Worker with a bounded timeout (src/lib/runFunctionJob.ts), not on the server's own main thread. Earlier versions called the built function synchronously in-process, so a while (true) {} source string would block the entire stdio server forever — every other in-flight or future tool call along with it. Now, if the worker doesn't finish within the timeout (default 10 seconds, override with the HONESTY_MCP_WORKER_TIMEOUT_MS environment variable, in milliseconds, from 1 to 2147483647), it is forcibly terminate()d and the tool call returns a clear timeout error instead of hanging. Console output from the supplied code (console.log, console.error) is captured and written to the server's stderr with a [honesty-mcp worker] prefix, capped at 16 KiB per call, so it doesn't reach stdout, which carries the MCP protocol. Code that writes to file descriptor 1 directly (for example with fs.writeSync(1, ...)) is not intercepted and can corrupt the protocol stream; that is part of why this is not a sandbox. This is not a sandbox — the worker has this process's full OS-level privileges (filesystem, network, environment variables) — it only bounds time. It does not stop caller code from reading your filesystem, making network requests, or doing anything else this Node process itself can do. The trust model above still applies in full: only pass code you wrote or trust, and don't expose this server to untrusted, remote, or adversarial input.

Kit versions

This server depends on the newer release line of each wrapped kit (the ranges in package.json). The table lists what that line changes compared with the 0.2 line that honesty-mcp 0.2.x used. At start-up each tool reads the installed kit's version, words its description for that version, and refuses an input that the installed kit would silently ignore (for example matchIdentifierParts with payout-invariance-kit 0.2, if an override installs it) instead of pretending it worked.

Kit

Version

What it changes through this server

grounding-kit

0.3.0

Each unit carries reasons, and the result lists nonClaims. Verdicts move in both directions (sentence boundaries after abbreviations, closing quotes and dashes; rules and table separators are no longer units).

corroboration-kit

0.3.0

Sources count by independent origin. New inputs origin, derivedFrom and inferOrigins; the result gains groups. A verdict can only get stricter.

payout-invariance-kit

0.3.0

New input matchIdentifierParts; identifiers are trimmed and matched in any script; a runtime ranking function that returns nothing is an error.

mutation-invariance-kit

0.3.0

An edit made in place to a mutated input is an error; scenarios with the same name are renamed name (2).

trust-core

0.3.0

Anonymous scores change (small and single-source corpora score lower); new config.fullCountWeight; evidence dated in the future is scored as undated.

provenance-kit

0.3.0

Verdicts move in both directions (more negation cues and asserting idioms, look-alike letters). A trailing space in a custom phrase no longer prevents the prefix match.

claims-registry-kit

0.4.0

A claim more than maxAgeDays x 24 hours old is stale (exact milliseconds); a placeholder evidenceRef is unverified.

audit-chain-kit

0.3.0

The verify result gains entriesChecked.

advice-ledger-kit

0.3.0

An exact tie in the bad rate is not-holding (it was holding).

agent-receipt-kit

0.3.0

Scaffold only: the worked example's results gain snapshot and uncoveredFactKeys.

cost-governor-kit

0.3.0

Scaffold only: the guidance mentions the newer admission-control API.

test/kitCompat.test.ts runs the matching branch for whichever line is installed. With the current ranges that is always the newer line, so the older-line checks can be removed in a later release.

Honest limits

  • This server adds no guarantee beyond what the kit it wraps already documents. Every tool description was checked against its kit's own README "Honest limits"/"Limits" section as of the sibling-kit commits this branch was built against — read that kit's README for the full detail behind any one-line tool description or table row here. If a kit's own limits change later, this server's wording can drift out of sync again; nothing here re-checks that automatically.

  • check_payout_invariance, check_mutation_invariance, and compute_divergence's worker-thread timeout bounds time only, not behavior — see "A note on the code-execution tools" above. It is not a sandbox, and these paths are off unless HONESTY_MCP_ENABLE_CODE_EXEC=1.

  • SERVER_VERSION (src/server.ts) and package.json's version are still bumped by hand. test/drift.test.ts now fails if they, or the two versions in server.json, disagree, but nothing bumps them for you.

Development

To work on this server itself (rather than just use it), clone the repo and build from source:

git clone https://github.com/lkopietz3-byte/honesty-mcp.git
cd honesty-mcp
npm install          # resolves the 11 wrapped kits from the npm registry
npm run build         # compiles src/ -> dist/
npm start              # runs dist/index.js on stdio
npm run lint         # eslint . --max-warnings=0
npm run typecheck   # tsc --noEmit over src/ + test/
npm test             # vitest (code execution is switched on for the suite in
                      # vitest.config.mjs), spins up a real MCP Client/Server pair
                      # over the SDK's InMemoryTransport and calls tools
                      # end-to-end (see test/*.test.ts)
npm run build        # tsc -p tsconfig.build.json -- compiles src/ -> dist/
npm run smoke        # npm run build first, then node dist/smoke.js --
                      # a standalone script that does the same real
                      # client/server handshake, lists all tools, and
                      # calls one end-to-end
npm run verify       # lint + typecheck + test + build + smoke, in order
npm run audit:dependencies   # npm audit --package-lock-only --include=dev
                              # --ignore-scripts --audit-level=low

Project layout

src/
  index.ts                    entrypoint: connects the server to stdio
  server.ts                   createServer() -- builds the McpServer and registers every tool
  smoke.ts                    standalone smoke-test script (see npm run smoke)
  lib/
    result.ts                 CallToolResult helpers (jsonResult / errorResult)
    codeExec.ts               the HONESTY_MCP_ENABLE_CODE_EXEC switch and its default constant
    buildFunction.ts           reference copy of the source-to-function builder (tested; not called at runtime)
    runFunctionJob.ts          runs that function (or the divergence groupBySource case)
                               inside a worker_threads Worker with a bounded timeout
  tools/
    grounding.ts
    corroboration.ts
    payoutInvariance.ts
    mutationInvariance.ts
    trustIdentified.ts
    trustAnonymous.ts
    provenance.ts
    claimsRegistry.ts
    auditChain.ts               (append_audit_entry + verify_audit_chain)
    adviceLedger.ts              (grade_decision + compute_divergence)
    agentReceiptScaffold.ts
    costGovernorScaffold.ts
test/
  server.test.ts               end-to-end tests over a real in-memory MCP client/server pair,
                                covering every tool's known-good and known-bad input
  buildFunction.test.ts        unit tests for the source-string -> function builder
  runFunctionJob.test.ts       unit tests for the worker-thread job runner (normal jobs,
                                error propagation, timeout enforcement, env var parsing)
  workerTimeout.test.ts        end-to-end proof that the three code-execution tools stay
                                bounded by the worker-thread timeout instead of hanging
  codeExec.test.ts             the code-execution switch: unset, set, garbage values, other tools
  fileRead.test.ts             static-imports mode never reads a path the caller names
  drift.test.ts                versions and README tool list match the code

Available Tools

14 tools
append_audit_entryAppend a tamper-evident audit-chain entryA

Appends one entry to an append-only, hash-chained audit log and returns the new (longer) chain. Each entry's hash binds its payload, index, createdAt, a fixed format tag (formatVersion, currently "audit-chain-kit/v1"), and the previous entry's hash together, so any later tampering with an earlier entry -- or an entry produced by an incompatible version of audit-chain-kit -- breaks the chain in a way verify_audit_chain will detect. Use this wherever you need a tamper-evident record of events (agent actions, approvals, state transitions) that a skeptical third party can later verify independently. This function does not persist anything itself -- store the returned chain (or just the new entry) in whatever your app already uses.

Inputs: chain (required), payload (required).

assess_anonymous_authenticityScore how organic unattributed signals lookA

Scores how organic a corpus of UNATTRIBUTED, scraped sentiment signals (crawled mentions, imported reviews with no verifiable identity, aggregator feeds) looks, weighing a positive composite of consensus/diversity/volume/recency against a heuristic penalty for two specific, cheap manipulation patterns: evidence concentrated in a single source, and suspiciously uniform sentiment (near-maximal with near-zero variance -- the fingerprint of copy-pasted or purchased praise). This is NOT a fraud or astroturf detector: it cannot show that sentiment is fabricated or that any reviewer is fake, and a campaign that varies its wording/sentiment and spreads across several sources isn't caught by these two checks. Treat a low score as 'looks statistically unusual in a specific way worth a human look', not as a fraud finding. Use this for reviews/mentions/buzz with no identity behind them. For signals from known, identified contributors, use score_trust_identified instead.

Inputs: now (required), signals (required), config.

check_claims_registryCheck public claims for stale or missing evidenceA

Keeps public-facing product claims honest over time by checking each one against its own claimed evidence -- the SOC2-control-evidence pattern applied to marketing/product copy instead of compliance controls. Buckets every claim into 'current' (evidence present, review within policy), 'stale' (evidence present but verifiedAt is older than maxAgeDays, or unparseable), or 'unverified' (no evidenceRef at all -- this always wins over staleness, since a fresh date next to an empty reference proves nothing). Use this as a periodic 'Monday-morning' review or a CI gate on a claims registry, to catch marketing copy that drifted out of sync with what the product actually does after a refactor. Note: this only checks that a reference EXISTS and is fresh, not that the thing it points to still actually supports the claim's text -- pair with check_grounding for that.

Inputs: claims (required), maxAgeDays (required), now.

check_groundingCheck citation groundingA

Detects ungrounded or forged citations in AI-generated text. Splits text into sentences and classifies each one against evidence: 'grounded' (cites a marker whose evidence plausibly supports it), 'placeholder' (an honest 'TBD'/unknown gap, no fake citation), 'ungrounded' (a claim with no citation at all), or 'invalid' (cites a marker id that is missing from evidence, or whose evidence doesn't plausibly support the sentence under the default matcher -- i.e. a forged or hallucinated citation; this outranks every other status). This is a mechanical/structural check, not a truth checker: the default support check is naive substring/word-overlap matching, not semantic entailment -- it can pass a coincidental word match and can fail a genuine paraphrase, and it cannot verify that the evidence itself is true. Use this before shipping any AI-written report, summary, or answer that cites sources, to catch a model inventing or misattributing a citation. Treat any 'invalid' sentence as a hard stop; treat 'ungrounded' sentences as claims that should probably cite something but currently don't. For higher-stakes content, use grounding-kit directly with a custom supports() function (embedding-similarity or NLI-based) instead of the default matcher.

Inputs: text (required), evidence (required).

check_mutation_invarianceCheck whether a decision function ignores a given inputA

Checks -- for the scenarios you supply, not a formal proof for every possible input -- whether a decision, score, or ranking function's output changes depending on a variable it claims not to depend on: a protected attribute (name, inferred ethnicity/gender/age signal), geography, price, or any axis you name. Re-runs your actual function once per named mutation scenario and confirms the output is byte-identical to the unmutated baseline; a scenario whose mutation didn't actually change the input is flagged 'vacuous' rather than silently counting as a pass. This is the general form of check_payout_invariance -- use this one for hiring/lending/insurance/housing-style fairness claims or any other 'should not depend on X' claim; use check_payout_invariance specifically for the payout/commission axis (it also has a static-import-grep mode this tool doesn't need). Pass JS source for the function under test and each mutation -- this runs in a worker thread with a bounded timeout, not a sandbox, so only pass code you wrote or trust. A pass covers only the mutations you ran: it says nothing about values you didn't try, fields changed one at a time but never together, or a proxy field you never touched (a ZIP code standing in for race, a graduation year for age). Re-run this in CI whenever the function changes.

Inputs: fnSource (required), baseInput (required), scenarios (required).

check_payout_invarianceCheck whether a ranking engine ignores payoutA

Checks -- for the specific scenarios you supply, not a formal proof for every possible payout configuration -- whether a ranking/recommendation/comparison engine's output ordering changes depending on which option pays the operator more (affiliate commission, sponsored placement, referral fee). Two modes: runtime re-runs your actual ranking function under adversarial payout-mutation scenarios you name and confirms the result is byte-identical to the unmutated baseline (pass JS source for the ranking function and each mutation -- this runs in a worker thread with a bounded timeout, not a sandbox, so only pass code you wrote or trust; a scenario whose mutation didn't actually change the input is flagged 'vacuous' rather than silently counting as a pass). static-imports instead greps a set of source files for any reference to payout-related identifiers, to assert the ranking engine's code never even has payout data in scope -- no code execution needed for this mode, and it's a best-effort text/regex grep, not a real parser (it won't catch a dynamically-built import specifier or a re-export under an aliased name). Use runtime when you can call the ranking function directly; use static-imports as a cheaper, complementary check on the engine's source. A passing result means no difference in the scenarios tested, not that the function is payout-neutral in general -- write adversarial and boundary scenarios, not one easy case, and re-run this in CI whenever the ranking logic changes.

Inputs: mode (required), files, baseInput, mutations, +4 more.

check_provenance_claimsCheck claims for unbacked certainty languageA

Scans reader-facing claims for certainty-implying language ("(verified)", "independently verified", "guaranteed", "fact-checked", "100% accurate", ...) that isn't backed by an appropriate provenance tier, plus tiers that require a sourceRef but don't have one, and claims carrying an unrecognized tier. This is the exact pattern that caught ~150 false '(verified)' labels on a live site after they had already shipped -- run it on any copy, marketing page, or AI-drafted content that makes factual-sounding claims before it ships, not after. The default phrase list is a starting point drawn from that one incident, not a taxonomy -- it will miss phrases it doesn't know about (e.g. 'clinically proven', 'third-party tested'); extend certaintyPhrases for your domain. Negation detection is a fixed character window before a match, not a parser, so it can miss a negation in an earlier clause or over-suppress one further away. An empty result means every claim's certainty language (that this tool's phrase list and negation window caught) is backed by its tier.

Inputs: claims (required), caseSensitive, negationWindow, certaintyPhrases, +2 more.

compute_divergenceMeasure where two judges disagree, and who was rightA

Computes how often two independent judges (e.g. an automated engine and a human override) rated the same object differently, and -- where a later outcome exists to settle it -- reports engineRight and humanRight as two SEPARATE counts, never combined into one blended accuracy number (a system can be right most of the time overall and still wrong every single time a human bothers to overrule it, and that second fact is the one worth acting on). Divergence needs BOTH a count floor (minDivergentCount) and a rate floor (minDivergentRate) before it's 'reportable' -- either alone lets noise through. Calibration (who was right) carries its own separate floor (minResolvedDivergent) and its own status, so a population can legitimately have reportable divergence and refused calibration at the same time: plenty of disagreements, not enough of them settled by a later outcome yet. Supply group on each pair (or a custom config.groupBySource) to also get a sorted per-group breakdown alongside the overall report. Use this whenever a system has both an automated judgment and a human override/correction recorded for the same objects, to find out whether overruling the system is actually earning its keep. For grading one recommendation's own before/after outcome window instead of a whole population of engine-vs-human calls, use grade_decision.

Inputs: pairs (required), config.

corroborate_evidenceGrade evidence corroboration for a claimA

Grades confidence in a claim from a set of independent evidence signals -- NOT a vote count. 'confirmed' requires 2+ distinct supporting sources AND at least one non-textual signal; disagreement among sources surfaces as 'mixed' rather than being averaged away; a null result is 'not-found' only under adequate coverage, otherwise 'inconclusive' (a thin sample can't prove a negative); and thin coverage caps the verdict below 'confirmed' no matter how clean the signals look. Use this whenever several pieces of evidence were gathered for a claim (by you, another tool, or a research/verification pass) and you need an honest, non-inflated verdict instead of eyeballing how many checks 'passed'.

Inputs: signals (required), coverage (required).

grade_decisionGrade a decision against what happened after itA

Grades one recommendation-and-decision pair against a before/after observation log. Compares a pre-decision BASELINE window to a post-decision, exposure-aligned RESULT window on the same subjectId + checkKey, and returns 'holding' (the exposed post-decision window stayed under refuteThreshold bad observations AND its bad rate is not higher than the baseline's), 'not-holding' (EITHER the exposed post-decision window hit refuteThreshold bad observations, OR its bad rate is higher than the baseline's, even below that count -- 1 bad of 10 before, 1 bad of 3 exposed since is 'not-holding', not 'holding', despite the count staying under the default bar of 2), or 'refused' (the evidence didn't clear a floor -- see refusalCodes for exactly which one, never a vague 'unproven'). The rate comparison is exact -- it cross-multiplies the raw counts rather than comparing the rounded badRate fields or the sign of badRateDelta, so a not-holding can occur even when both windows display the same 3-place badRate. Always show badRateDelta and the raw baseline/result counts next to the verdict, don't quote 'holding' on its own. The verdict grades the DECISION, not just whether advice was taken: a DISMISSED recommendation whose problem later surfaced also grades 'not-holding', because the evidence sided with the advice either way. Two things this tool refuses to let slide: (1) 'nothing has gone wrong since' only counts as a result if the baseline shows the problem existed before -- otherwise it's 'baseline_lacks_negative_signal'; (2) only observations where the advice could actually have applied (exposed === true) can create or reverse the headline verdict -- everything else is reported separately as secondary (whose own wouldBeVerdict can itself be 'refused'), labelled non-headline, and can never become the headline. Use this to close the loop on any recommender/advisor system that logs recommendations, human accept/reject calls, and later outcomes, instead of letting advice quality go unmeasured forever. For grading a whole population of engine-vs-human calls at once (rather than one decision against its own before/after window), use compute_divergence instead.

Inputs: decision (required), observations (required), recommendation (required), config.

scaffold_agent_receiptsScaffold the agent-receipt-kit authorization patternA

agent-receipt-kit is a RUNTIME LIBRARY your own agent-orchestration code imports and calls at two specific moments (issue a WorkPacket before an agent runs, verify its AgentClaim after) -- it is not something this MCP server can 'check' on demand the way it checks a document's citations, because the packet only exists inside your application's own runtime. Call this tool to get the pattern explained, an install step, a copy-pasteable starter snippet for wiring issuePacket/verifyReceipt into your own agent loop, and (optionally) a live worked example run against the real kit -- one accepted claim, one rejected claim -- so you can see actual output before wiring it in. Use this when you're building or reviewing anything that lets an AI agent report back what it did (a coding agent, a browser-automation agent, a data-processing agent) and you don't yet trust that report by construction.

Inputs: includeWorkedExample.

scaffold_cost_governorScaffold the cost-governor-kit spend-safety patternA

cost-governor-kit is a RUNTIME LIBRARY your app installs and calls at the moment it's about to make an AI API call -- it is not something this MCP server can 'check' on demand the way it checks a document's citations. Its advisory check-then-commit piece (withReserveConfirm) needs a live UsageLedger backed by YOUR database and an async callback making the real call, neither of which exist as content to hand this tool. Call this to get all three pieces explained (estimated pre-call spend check, cache-aware pricing math, advisory successful-call usage counting), an install step, a copy-pasteable starter snippet, and (optionally) a live worked example: real checkPreCallCeiling calls (one allowed, one blocked), a real withReserveConfirm run against an in-memory demo ledger (one call under the limit, one over, one whose commit fails after a successful call), and a real estimateCostUsd comparison of the default 0.1x cache-read rate against a caller-supplied cacheReadPerMillion override. Use this when you're building or reviewing anything that calls a paid AI API and want a pre-call spend estimate plus usage counting that skips a call that threw -- NOT a strict concurrent limit and not proof a timed-out call was never billed by the provider (see concurrency_and_recovery in the output, and use withCapacityReservation instead if you need a real reservation).

Inputs: includeWorkedExample.

score_trust_identifiedScore an entity from known contributorsA

Scores one entity (or one dimension of one entity -- quality, reliability, communication, ...) from signals contributed by KNOWN, identified sources: reviewer accounts, raters, inspectors, verified buyers. Weighs each signal by tier x source x proof-strength x reputation x recency decay, sums to an effective (credibility-weighted) sample size, and shrinks the result toward a domain baseline ('prior') by a configurable dial -- thin evidence stays close to the prior, deep evidence overrides it. Use this for trust/reputation scores backed by attributable evidence. For unattributed/scraped signals with no identity behind them, use assess_anonymous_authenticity instead.

Inputs: now (required), prior (required), signals (required), dial, +1 more.

verify_audit_chainVerify a tamper-evident audit chainA

Independently re-verifies a hash chain from genesis: recomputes every entry's hash and confirms each entry's prevHash matches the preceding entry's entryHash. Detects a mutated payload (stored entryHash no longer matches recomputed hash) and a severed link or spliced-out middle entry (prevHash mismatch) with no options at all. Two DIFFERENT truncation attacks need two DIFFERENT options, and neither is on by default: (1) entries deleted from the end and NOT replaced -- pass expectedMinLength to catch a chain that's simply shorter than it should be (a tail deletion alone leaves no broken pointer for the walk to find); this does NOT catch truncate-and-re-append (deleting tail entries and then appending new, self-consistent ones to reach the same length again -- expectedMinLength sees the 'right' length and passes). (2) to catch truncate-and-re-append, pass anchor: an { index, entryHash } checkpoint you saved earlier from a source the chain's writer cannot edit (your own log, a separate append-only store). The chain is invalid unless the entry at anchor.index has exactly that entryHash -- this also catches a full rewrite from genesis, but entries after the anchor are only checked for internal consistency, not against anything external. Passing neither option means a truncate-and-re-append (or a full rewrite from genesis) can pass as 'valid'. Proves the chain is internally consistent and unaltered since it was hashed (and, with anchor, unaltered up to the anchor point); it does NOT prove nobody with write access ever rewrote the whole chain from genesis when no anchor is supplied (tamper-evident, not tamper-proof). Use this to audit a chain you did not produce yourself before trusting it.

Inputs: chain (required), anchor, expectedMinLength.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.2/5.0

    Scored across 14 tools

    Disambiguation4/5

    Most tools target clearly distinct concerns (citation grounding, evidence confidence, invariance, trust scoring, provenance, audit chain, decision grading), and each description explicitly names when to use a sibling tool instead. The one real soft spot is check_payout_invariance vs check_mutation_invariance, where the former is described as a special case of the latter, plus some conceptual overlap between check_provenance_claims and check_claims_registry, though the descriptions disambiguate both.

    Naming Consistency4/5

    All names follow a uniform snake_case verb_noun pattern (check_grounding, corroborate_evidence, append_audit_entry, verify_audit_chain, grade_decision, etc.). Verb choice varies (check/score/assess/grade/compute/scaffold) to reflect genuinely different actions, but the structural convention is consistent throughout.

    Tool Count4/5

    14 tools sits comfortably in the healthy 3-15 range, and each has a distinct, non-trivial purpose rather than being padding. The set is broad (citation checks, invariance tests, trust scoring, audit chains, decision grading, and two scaffold helpers), so it functions more as a curated honesty toolkit than a single tightly-scoped domain, but no tool feels redundant.

    Completeness4/5

    Coverage is broad for an 'honesty/integrity' toolkit, with natural pairs such as append_audit_entry/verify_audit_chain and score_trust_identified/assess_anonymous_authenticity covering both sides of each concern. Minor gaps exist (e.g. no dedicated truth-of-evidence checker, and grounding explicitly defers semantic entailment to an external kit), but the surface covers the stated intent without obvious dead ends.

    Related MCP Connectors

    Related MCP Servers