build / @flop-lab/mcp
FLOP MCP client
This shared client is imported by other packages. It has no flop subcommand.
Reading progress
FLOP MCP client
How do I read FLOP's public data without rebuilding the transport? This shared client parses the hosted server's event stream, checks response shapes and returns each observation with its source and time. The tools in this repository use the same client and recorded responses.
Quick start
From the repository root with Node 22 and pnpm. This reads public network stats:
pnpm install --frozen-lockfile
pnpm --filter @flop-lab/mcp check
pnpm exec tsx -e 'import { McpClient, getStats } from "./packages/mcp/src/index.ts"; getStats(new McpClient()).then(console.log)'Transport and typed helpers
- JSON-RPC 2.0 over POST, answered as server-sent events. Session-less.
- Retries with backoff on network errors, timeouts, 429 and 5xx.
Retry-Afteris honoured. 4xx other than 429 is never retried. - One request at a time per client, spaced by
minIntervalMs(250 by default), so a tool cannot hammer the shared service. - Typed helpers with runtime checks for the answers the tools in this repo use:
getStats,listSettlements,listAllSettlements,listSessionOffers,getComputeChannel,getTrustRoot,getPouiLeaderboard,indexerQuery. - Amounts stay integer strings (18 decimals). Use
BigIntto compute.escrowConservedchecksminerPaid + unusedEscrow + burned = escrowexactly. - Recorded answers in
fixtures/(2026-11-05) andreplayFetch()for tests:import { replayFetch } from "@flop-lab/mcp/fixtures".
import { McpClient, getStats, listSettlements } from "@flop-lab/mcp";
const mcp = new McpClient();
const { value: stats, measuredAt } = await getStats(mcp);
const page = (await listSettlements(mcp, { limit: 20 })).value;The server rejects the default Python-urllib user agent with HTTP 403. This client sends flop-lab/0.1 (+https://github.com/zkasuran/flop-lab).
Typed indexer reads
readIndexer(client, entity, args) uses fixed selections and GraphQL variables.
It returns the query, variables, source, raw response and measurement time with validated data.
Use readIndexer(client, "block", { number: 100 }) for a block or
readIndexer(client, "computeChannels", { limit: 20, offset: 0 }) for a page.
Selections cover blocks, transactions, accounts, HTLCs, channels, settlement prices,
PoUI proofs, reliability events, miner reliability, sponsor positions and account totals.
Nullable fields remain null. Integer token amounts remain strings. Invalid shapes fail closed.
List reads default to 20 rows with a maximum of 100. No helper auto-paginates.
Blocks, transactions, HTLCs, proofs and sponsor positions return arrays without a total.
Channels, prices and reliability events return data and pagination.
fixtures/indexer-schema.json records full schema introspection including arguments,
defaults and nested types. The other indexer-*.json files retain raw tool text and capture times.
The schema does not expose transaction fees, transaction events or a block transaction filter.
A bounded recent transaction list is not a complete block transaction history.
What this does not verify
It validates the shape of the answers it types, not their truth. Some tools of the server are documented as simulated (flop_verify_tee_quote) or partly placeholder (flop_get_inference_receipt). Do not present them as proof.
Set FLOP_LIVE=1 to run the one live test. The recorded fixtures will drift from the network over time.