SolvaDocs

AI tools

Read these docs as Markdown from an AI assistant, and query coverage records with the oracle's two MCP tools.

An AI assistant reads these docs as Markdown. The oracle, an MCP server, answers an assistant's questions about an institution's record.

These docs as Markdown

Every page is available as plain Markdown, built from the same source as the HTML page.

URLWhat it returns
https://docs.joinsolva.xyz/llms.txtAn index of every page, with its title, description and a link to its Markdown version.
https://docs.joinsolva.xyz/llms-full.txtEvery page in one Markdown file.
https://docs.joinsolva.xyz/docs/<page>.mdOne page. Add .md to any page URL, for example /docs/build/quickstart.md. The docs home is /docs.md.

Each Markdown page starts with the page title and description. Each HTML page also points to its Markdown version with a text/markdown alternate link in its head.

Give an assistant llms.txt when it should find the right page itself, and llms-full.txt when it should read everything at once.

Page actions

Under every page title:

  • Copy Markdown copies the page's Markdown to your clipboard.
  • Open shows a menu: Open in GitHub, View as Markdown, Open in Scira AI, Open in ChatGPT, Open in Claude and Open in Cursor. The assistant links open with the prompt "Read <page URL>, I want to ask questions about it."

The oracle

The oracle is an MCP server in services/oracle. MCP, the Model Context Protocol, is how an AI assistant calls tools that a server exposes. The oracle exposes two tools about an institution's coverage: get_solvency and get_anomalies. It runs over stdio.

Answers from a live orchestrator Coming soon depend on the SDK's orchestrator calls, which the oracle reads through. The tools, their inputs and their outputs are described below as they work once those calls match the orchestrator.

Run it

From the repository root, build it and point your MCP client at the built server:

pnpm exec turbo run build --filter=@solva/oracle
mcp.json
{
  "mcpServers": {
    "solva-oracle": {
      "command": "node",
      "args": ["/path/to/solva/services/oracle/dist/server.js"],
      "env": {
        "SOLVA_NETWORK": "testnet",
        "SOLVA_ORCHESTRATOR_URL": "http://localhost:8080",
        "SOLVA_CONTRACT_ID": "CAFUK25F56VW442VAOHDKGMPYF2BZ3ERVLVAM4H6JTN2WGZPDUQLRTPN"
      }
    }
  }
}
VariableDefaultMeaning
SOLVA_NETWORKtestnettestnet, mainnet or local. Picks the SDK's default endpoints.
SOLVA_ORCHESTRATOR_URLthe SDK defaultOrchestrator the oracle reads stored proofs from.
SOLVA_RPC_URLthe SDK defaultSoroban RPC for the on-chain read.
SOLVA_CONTRACT_IDnoneA registry to read. When unset, the SDK asks the orchestrator for the institution's registry.
SOLVA_API_TOKENnoneSent as a bearer token on orchestrator calls.

get_solvency

Returns whether an institution's reserves cover its liabilities, confirmed by a read of its own registry on Stellar.

Input

FieldTypeMeaning
institution_idstring, at least 1 characterThe institution's tenant UUID.

How it answers. It reads the institution's latest stored proof through the SDK's getLatestProof. It then reads the latest proof from the institution's registry on chain with getOnChainLatestProof and checks that R >= L there. If the on-chain read fails, it reports verifiedOnChain: false instead of an error.

Output. One text item holding this JSON:

{
  "status": "solvent",
  "solvent": true,
  "reservesTotal": "16000000",
  "liabilitiesTotal": "9000000",
  "proofId": "1",
  "verifiedOnChain": true,
  "asOf": 1793685990
}
FieldTypeMeaning
statusstringsolvent when covered and confirmed on chain, otherwise breach.
solventbooleantrue only when the on-chain read succeeded and reserves cover liabilities.
reservesTotalstringR, minor units.
liabilitiesTotalstringL, minor units.
proofIdstringThe proof's id.
verifiedOnChainbooleantrue when the on-chain read succeeded and showed R >= L.
asOfnumberWhen the proof was published, Unix seconds.

The field and value names are the tool's API. In these docs the same idea is called coverage: solvent: true means the record shows reserves covering liabilities.

get_anomalies

Returns flags raised by comparing each of an institution's proofs with the one before it. It uses only the public totals and timestamps, so it needs no private data.

Input

FieldTypeMeaning
institution_idstring, at least 1 characterThe institution's tenant UUID.

Output. One text item holding a JSON array of flags:

[
  {
    "kind": "reserve_drift",
    "severity": "critical",
    "proofId": "2",
    "value": -40.62,
    "threshold": -10,
    "message": "Reserves fell 40.62% from the previous cycle.",
    "detectedAt": 1793772390
  }
]
FieldTypeMeaning
kindstringreserve_drift, liability_spike or cycle_timing_gap.
severitystringwarning at or past the threshold, critical at twice the threshold or more.
proofIdstringThe later proof of the two compared.
valuenumberThe measured change in percent, or the gap in seconds.
thresholdnumberThe threshold crossed. Negative for reserve drift.
messagestringA plain sentence describing the flag.
detectedAtnumberPublish time of the later proof, Unix seconds.

The thresholds are DEFAULT_THRESHOLDS in packages/shared-types/src/anomaly.ts:

FlagRaised whenDefault
reserve_driftReserves fall by at least this percent from the previous proof. A rise never raises it.10%
liability_spikeLiabilities rise by at least this percent from the previous proof.15%
cycle_timing_gapMore than this many seconds pass between two proofs.93,600 s (26 hours: a daily cycle plus 2 hours)

Percent changes are computed on the integer totals with BigInt and truncated to two decimal places.

A flag needs two proofs to compare. Today the oracle passes only the latest proof, so get_anomalies raises no flag yet. Reading the full proof history comes with answers from a live orchestrator. The example above shows the shape a flag takes. A move from solvent (16,000,000) to near-breach (9,500,000) is a 40.62% fall, more than twice the 10% threshold, so it is critical.

Next: Changelog.

On this page