Kaval

io.github.usekaval由 GitHub 帳號 usekaval 發布v0.8.2更新於 Oct 24, 2026

Verify the facts an agent's action depends on before it acts — ALLOW, REVIEW, or BLOCK.

概覽

AI 產生的概覽

Kaval 在 AI 代理執行動作前核驗該動作所依據的事實,回傳 ALLOW、REVIEW 或 BLOCK 及簽章回執,是託管 Kaval API 的輕量用戶端。

可以做什麼
檢查即將執行的動作或一組主張,回傳決策、逐條事實狀態與簽章回執;依回執 id 取得完整簽章文件,並在事後回報實際結果以供校準。管理受監看來源:註冊網址、具名權威機構或推送文件,列出、更新、綁定抽取結構,並移除來源以釋出工作區名額。處理合約:建立私有 PDF 上傳目標,將文字或文件排入抽取,查看狀態,列出抽取出的主張與抽取問題,並核准、更正或拒絕主張。執行綁定結構的抽取:註冊 JSON Schema,發起依發布者與期間的一次性抽取,查看執行狀態與結果,列出每月打包。
適用情境
適用於 AI 代理即將執行重要動作、需要確認其依據的事實仍然成立時,或需要該決策的可稽核簽章紀錄時。也適合從受監看的發布者文件中抽取結構化紀錄並審核合約主張的團隊。
執行需求
以 npm 套件形式透過 stdio 在本機執行(npx @usekaval/mcp),僅限桌面端。需要在 KAVAL_API_KEY 中提供 Kaval API 金鑰;KAVAL_BASE_URL 為選用,可指向自架或預備環境 API。需要能連線至 Kaval API 的網路;不需模型或搜尋金鑰。
安裝前請注意
會將提交的動作、主張與文件傳送至託管的 Kaval API,編譯、依據檢索與擷取都在伺服器端完成。API 金鑰是 bearer 憑證,應妥善保密。許多工具會寫入或變更狀態:合約上傳與主張審核、事實匯入、來源註冊與移除、結構建立與刪除、抽取執行以及訓練回饋同意。移除來源會將其遺忘,且只有刪除才能釋出工作區名額。REVIEW 絕不代表可以執行。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 Kaval,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

@usekaval/mcp

Before an AI agent acts, Kaval verifies the facts that action depends on and answers ALLOW, REVIEW, or BLOCK with a signed receipt. This package exposes that as an MCP server.

Policy engines decide whether an action is permitted under the rules; Kaval verifies whether the facts those rules depend on are still true.

This package is a thin client over the hosted Kaval API. All compilation, grounding, and retrieval run server-side, so you bring just a Kaval API key — no model or search keys, no local engine.

0.6 was a breaking release. Nine tools became seven (before later portfolio/extraction tools landed), and everything removed folded into check; the API answers 410 tool_retired for the old routes and this server translates that into an error that tells the agent to call check. See Migrating from 0.5.

Run it

bash
npx -y @usekaval/mcp

It speaks MCP over stdio. Point any MCP client at it.

Client config

jsonc
{  "mcpServers": {    "kaval": {      "command": "npx",      "args": ["-y", "@usekaval/mcp"],      "env": {        "KAVAL_API_KEY": "kv_live_…",      },    },  },}

Tools

ToolWhat it does
checkThe one that does the work. Send the action you are about to take (or the claims it rests on) → ALLOW / REVIEW / BLOCK, per-fact status, and a signed receipt.
get_receiptThe full signed document behind a check's receipt.id — per-fact evidence basis, decision-rule version, signing key. What an agent attaches when it blocks.
prepare_contract_uploadCreate a private PDF upload target.
ingest_contractQueue canonical text, an HTTPS document, or an uploaded PDF for extraction.
get_contractGet contract processing status, candidate counts, and extraction issue state.
list_contract_claimsList extracted candidates with exact evidence spans.
list_contract_extraction_issuesList deterministic extraction failures that need customer review.
review_contract_claimApprove, correct, or reject one candidate with immutable version control.
import_factsQueue up to 400 reviewed facts for warm checks.
get_fact_importGet one bulk import and every item result.
list_bulletinsSoft-deprecated — filter structured bulletins by payer, policy, code, date, or status. Prefer list_extraction_runs for new integrations.
get_bulletinSoft-deprecated — get one structured bulletin with field evidence. Prefer get_extraction_run.
list_bulletin_extraction_attemptsSoft-deprecated — list customer-readable bulletin extraction status and failures. Prefer list_extraction_runs.
get_bulletin_extraction_attemptSoft-deprecated — get one bulletin extraction attempt by source-version id. Prefer get_extraction_run.
list_training_jobsList read-only training and evaluation status.
get_training_jobGet one read-only training job.
list_training_feedbackList reviewed feedback and its effective training-use state.
record_training_feedback_consentRecord an explicit training-use decision for one reviewed feedback item.
create_extraction_schemaRegister a JSON Schema Kaval extracts structured records against. Requires policy-update:manage.
list_extraction_schemasList the extraction schemas registered in this workspace.
create_extraction_runRequest a one-off publisher + period extraction run against a bound schema. Requires policy-update:manage.
get_extraction_runGet one extraction run by id — status, schema, and result once it succeeds.
list_extraction_runsList extraction runs with publisher/period/time filters, cursor pagination, and nested document chrome (pass expand_document: false to omit).
list_extraction_packagesList the monthly PDF + manifest rollups extraction runs are packaged into.
list_publishersList org-owned publishers for this workspace's billing account.
create_publisherCreate an org-owned publisher (UUID identity; renameable display name).
get_publisherGet one org-owned publisher by UUID.
update_publisherRename an org-owned publisher. UUID identity is unchanged.
add_sourceTell Kaval what to watch — requires publisher_id (org publisher UUID). A URL, a named authority to resolve, or a document you will push in.
list_sourcesWhat Kaval currently watches for this workspace, including sources it auto-registered after a check cited them.
remove_sourceStop watching a source and forget it. The only thing that frees a registered/resolved workspace slot (auto-registered citations count there; discovered children use a separate per-parent ceiling).
update_sourceBind (or unbind) an extraction schema and/or set publisher_id on a watched source. Pass reprocess: true to fill-missing re-extract prior versions. Requires policy-update:manage.
get_source_version_contentFetch the captured content of one fetched source version, as raw text or pre-split sections.
report_outcomeReport what actually happened after a prior check (by receipt.id), so Kaval can calibrate.
verifyDeprecated pilot alias: one conclusion + explicit evidence_refs → a signed ProofPacket receipt. Use check.

Resources

The server publishes these JSON resources:

  • kaval://bulletins
  • kaval://bulletins/extraction-attempts
  • kaval://training-jobs
  • kaval://training-feedback
  • kaval://contracts/{contract_id}
  • kaval://contracts/{contract_id}/claims
  • kaval://contracts/{contract_id}/extraction-issues
  • kaval://bulletins/{source_version_id}
  • kaval://bulletins/extraction-attempts/{source_version_id}
  • kaval://fact-imports/{import_id}
  • kaval://training-jobs/{job_id}

The training resources are read-only. Feedback review and consent require training:manage.

Bulletin extraction status is read-only. MCP does not expose the operator requeue control.

MCP does not start training or promote a model.

check

jsonc
// arguments{  "action": "Approve this prior-authorization request at the in-network rate",  "context": "payer: Aetna; CPT 12345; plan HMO",  "materiality": "critical",}

Or skip extraction entirely by naming the facts:

jsonc
{  "claims": [    {      "subject": "Aetna",      "predicate": "requires_prior_auth_for",      "object": "CPT 12345",      "scope": { "plan": "HMO", "state": "CA" },    },    "The 2024 IBC is the current edition",  ],  "mode": "fast",}

The response:

fieldmeaning
decisionALLOW — every material fact still holds on fresh evidence, proceed.
REVIEW — something is unknown, mid-re-evaluation, or changed at low/medium materiality. REVIEW is never permission to act.
BLOCK — a high/critical fact changed, or a critical fact is unknown.
reason_codesone or more of ALL_FACTS_HOLD, FACT_CHANGED, FACT_EXPIRED, FACT_UNKNOWN, SOURCE_UPDATED_PENDING_REVIEW, SOURCE_UNREACHABLE, NEW_FACT_UNVERIFIED, COMPILATION_UNCERTAIN
facts[]{ fingerprint, text, status: holds | changed | unknown, materiality, served_from_state, last_verified_at, sources[] } — this is how you see which belief moved
receipt{ id, signature, signed_at }. Pass receipt.id to report_outcome, or to get_receipt for the full signed document
latency_ms{ compile, lookup, live, total }

mode: "fast" answers only from stored state and reports anything unknown as unknown; "standard" (default) may research a stale or novel fact within max_wait_ms. A fact that misses the budget comes back unknown — it does not warm the next check, because that check recompiles the action and asks about different fact fingerprints.

The budget. The API's own default is 100000 ms, because a cold action check with several novel premises routinely needs 50–100s of live research. MCP cannot spend that: an MCP client cancels a tool call after 60s. So this server sends max_wait_ms: 45000 explicitly and caps the argument there, and gives its HTTP client a 55s deadline so the timeout fires here — as {"error":"timeout"} with a recovery move — rather than as a cancelled request. Pass a smaller max_wait_ms when a bounded REVIEW beats waiting; 0 disables research entirely, which is what mode: "fast" does. Direct HTTP and SDK callers are not bound by any of this and get the full 100000.

A fact already backed by a watched source is answered from stored state with zero model calls and zero fetches, so calling check on every consequential action is cheap. A fact Kaval has never seen has to be researched first, and that takes seconds.

Keeping checks warm

add_source is what makes a check a database read instead of a research run. Registering the name of an authority is usually enough:

jsonc
{ "kind": "entity", "name": "Aetna", "intent": "payer policy bulletins" }

Kaval resolves that to the pages that publish it and watches them adaptively. kind: "url" watches one page; kind: "push" is a document your own system sends to POST /v1/events. Registering is optional — a source a check cites is auto-watched — but registering first is what makes the first check on a fact fast.

That auto-watching is why remove_source exists. Capacity is two ceilings, not one:

  • up to 200 active registered / resolved sources per workspace (auto-registered citations count here; discovered children do not)
  • up to 200 active discovered children per parent

Only deletion frees a slot — pausing does not. An agent that registers per task and never removes will eventually fill the workspace registered/resolved ceiling, after which new citations are dropped silently and checks that used to be warm go back to researching. Remove what a task registered when the task is done.

Extractions

create_extraction_schema registers a JSON Schema; bind its id to a watched source with update_source({ id, extraction_schema_id }) and every document that lands on that source afterward is extracted against the schema automatically — no polling. Pass reprocess: true to also fill-missing re-extract versions that already ran under another schema; those webhooks carry source_change: "schema_changed" (join the original extract on source_version_id). For a one-off run against a publisher + period instead of waiting for the next document, call create_extraction_run directly. Either way, get_extraction_run / list_extraction_runs report the run's lifecycle (processing → retry → succeeded / review_required / failed), and list_extraction_packages lists the monthly PDF + manifest rollups each publisher/period is packaged into. Each package's pdf_href is a durable Kaval URL — GET (or HEAD) it and follow the 302 to a short-lived signed PDF (MCP does not expose a separate download tool; use HTTP with redirects). get_source_version_content fetches the canonical text (or format: "sections") an extraction run was computed from.

This is the schema-bound successor to the free-text bulletin tools (list_bulletins, get_bulletin, list_bulletin_extraction_attempts, get_bulletin_extraction_attempt), which are soft-deprecated but keep working.

Delta webhooks are not an agent tool

Watched sources are only half the mechanism: when a source changes, Kaval re-evaluates the dependent facts and pushes a fact_state.delta webhook naming what flipped; a source with a bound extraction schema also pushes extraction.document (and, monthly, extraction.package) with the extracted records (nested evidence on each record) and optional section page/bbox for PDF highlighting. extraction_run.period is the publication / newsletter month. Those subscriptions are deliberately not exposed as MCP tools. They are one-time deployment configuration — each mints a standing outbound callback bound to an https endpoint and a signing secret that must be stored, which is a deploy-time decision for a human or a service, not an in-loop choice for an agent that owns neither the endpoint nor the secret.

Configure them once from the SDK (kaval.subscribeFactStateDeltas({ callback_url }) / kaval.subscribeExtractions({ callback_url }) in Node, kaval.subscribe_fact_state_deltas(…) / kaval.subscribe_extractions(…) in Python), from POST /v1/webhooks with subscription_kind: "fact_state" or "extraction" (policy_update is rejected on create), or from the dashboard. The agent then just calls check (or reads list_extraction_runs), and it is already fast and already current.

Migrating from 0.5

0.5 tool0.6
currentness_checkcheck — { action } or { claims: ["…"] }
currentness_verifycheck — branch on decision === "ALLOW" instead of act === true
currentness_extract_and_checkcheck — pass the paragraph as action/context; Kaval compiles the facts itself
currentness_scan_storecheck — { claims: [...] }, up to 20 per call
currentness_monitoradd_source + a fact_state webhook subscription (see above) — deltas are pushed to you
proof_auditcheck — the receipt is the proof; get_receipt returns the signed document
proof_gatecheck — the warm path re-checks from stored state, so there is nothing to re-apply
report_outcomereport_outcome (unchanged; pass receipt.id)
verifyverify, now deprecated → move to check

Status mapping: current + act: true → decision: "ALLOW" with every fact holds; stale/contradicted → a fact changed (REVIEW or BLOCK by materiality); unsupported/insufficient/conflicting → a fact unknown (REVIEW, or BLOCK if critical).

A 0.5 client calling a removed route gets 410 {"error":"tool_retired","replacement":"/v1/check"}, which this server surfaces as {"error":"tool_retired","message":"this capability was folded into the check tool …","status":410}.

Idempotency

Contract uploads, contract creation, claim reviews, fact imports, create_extraction_schema, create_extraction_run, and verify carry operation keys. The server creates a key when you omit one. Reuse the returned key after an ambiguous failure.

check deliberately carries none: it is a read of current state, so a retry recomputes rather than replays and cannot double-count.

Tool errors

A failed tool call returns isError: true and a JSON body naming what happened, so an agent can branch on it rather than parse prose.

errorwhat to do
any API code (unauthorized, subscription_required, bad_request, …)returned verbatim with status and the API's message
tool_retired410 — the message names the route that replaced the one you called
timeoutretry with mode: "fast" or a smaller max_wait_ms
network_unreachablethe API was never reached — check KAVAL_BASE_URL and network access
request_ambiguousan idempotent call whose outcome is unknown; retry with the returned idempotency_key

Signed receipts

Check receipts are Ed25519-signed and self-derivable: because the decision table is published, the receipt's own fact list re-derives the verdict offline, byte for byte, with no server. Verify one with @usekaval/kaval/verify — a dependency-free subpath of the Node SDK this package already depends on, plus the kaval-receipt-verify CLI that SDK ships. It answers cryptographic validity, key trust, and freshness separately, needs no Kaval account and no API key, and reads the public keys from the unauthenticated GET /v1/proof-verification-keys/:kid — or from a keyset you archived beside the receipt, which is the fully offline path.

bash
npx -p @usekaval/kaval kaval-receipt-verify verify receipt.json \  --key-url https://api.usekaval.com/v1/proof-verification-keys

check returns only { id, signature, signed_at }. Call get_receipt with that id for the document that was actually signed — every fact with its state, the evidence basis under it (source locator, content digest and what the digest covers, fetch and publication time), the decision-rule version, and the signing key id. That is the artifact to attach to a BLOCK you escalate.

Honest boundaries: demo results carry no organizational authority; a production ALLOW requires a customer-bound action policy and applicable empirical calibration; REVIEW is never permission to act.

Environment

VarRequiredPurpose
KAVAL_API_KEYyesBearer key for the hosted Kaval API (create one at https://usekaval.com)
KAVAL_BASE_URLnoOverride the API base URL (self-hosted / staging). Defaults to https://api.usekaval.com

Both are declared in server.json and smithery.yaml, so a registry install can point at a self-hosted deployment rather than only at the hosted API.

The marketing site uses KAVAL_API_URL for its /api/verify proxy — not KAVAL_BASE_URL.

Programmatic use

This package is primarily a CLI (kaval-mcp). It also exports the server factory for embedding:

ts
import { createMcpServer, createClientFromEnv } from "@usekaval/mcp";
const server = createMcpServer(createClientFromEnv());// connect `server` to your own MCP transport

Or pass your own configured client:

ts
import { createMcpServer } from "@usekaval/mcp";import { Kaval } from "@usekaval/kaval";
const server = createMcpServer(  new Kaval({ apiKey: process.env.KAVAL_API_KEY }),);

Use delete_extraction_schema with { "id": "<schema-id>" } to delete an unused schema. Deletion removes the schema from lists and selectors. Historical extraction records retain its definition. If an active watched source uses the schema, the API returns 409 schema_in_use.

Use rename_extraction_schema with { "id": "<schema-id>", "name": "New name" } to rename a schema. Its definition and hash remain unchanged.

來源:packages/mcp/README.md,提交 e482bf8

工具

0
SourceWeft 尚未在沙箱中啟動過該軟體包,因此其工具未知。

版本歷史

1
  1. v0.8.2最新Sep 16, 2026

評分

已滿足適用檢查項的 50%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分

    請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。

  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具15 分

    請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。

  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分