OnChainDiligence โ MCP Server
Accountability infrastructure for consequential autonomous actions.
Payments are our first consequential action, not our definition of one.
Current wedge: agent commerce / payments.
Know why your agent paid โ and verify what happened afterward.
Keep your wallet. Keep your payment provider. Add OCD once.
Core primitive: an OCD Action Receipt, backed by an Agent Evidence
graph โ Mandate โ Evidence โ Policy โ Decision โ Execution โ
Observation/Reconciliation โ Verifiable Receipt. Sanctions/company checks
(Chainalysis, UK Companies House, SEC EDGAR) still exist and are fully
supported, but they are Evidence Providers โ supporting capabilities the
lifecycle can call on, not what the company is primarily about.
This repo is the MCP server โ mcp.onchaindiligence.com โ one of three
rails (HTTP API, Bazaar x402 routes, MCP)
that all produce the same signed evidence. Part of
onchaindiligence.com.
1. What OnChainDiligence is now
The original thesis: consequential autonomous actions should leave behind
evidence that can be independently verified later. The current product wedge
is agent commerce โ an agent proposing, executing, and settling a payment โ
because that's where the evidence problem is sharpest and most valuable
today. The same evidence graph (mandate, evidence, policy, decision,
execution, independent observation) generalizes beyond payments; payments
are the first profile it's built for, not a permanent ceiling.
OCD is not the wallet, the executor, or the payment provider. It never
holds funds, never signs a payment, and never overrides your own
wallet/provider's authorization. It evaluates proposed payments against your
policy, independently observes what actually settled, and issues a signed,
independently verifiable receipt reconciling the two.
2. Agent payment lifecycle
Mandate/Intent โ Evidence โ Policy โ Decision โ Execution โ Observation/Reconciliation โ Verifiable Receipt
inspect_payment (free, deterministic sanity-check)
โ
โผ
preflight_payment ($0.01) โโโบ PREFLIGHT receipt (ALLOW / REQUIRE_APPROVAL / BLOCK)
โ + one-time finalization capability
โผ
your own wallet/executor authorizes and submits the payment
โ (OCD never holds a key or signs)
โผ
OCD independently observes settlement on-chain
โ
โผ
finalize (free, using the capability) โโโบ Commerce Receipt
(execution + settlement, reconciled)
Full write-up: docs/PAYMENT_PREFLIGHT.md,
docs/COMMERCE_RECEIPTS.md, and the
flagship autonomous payment reference.
First integration: Pilot Quickstart.
3. Public/free verification MCP
https://mcp.onchaindiligence.com/public/mcp โ a separate, free,
unauthenticated MCP surface, deliberately non-transactional. Three tools:
| Tool | What it does |
|---|
inspect_payment | Deterministic policy comparison only โ ALLOW / REQUIRE_APPROVAL / BLOCK. No external lookups, signing, storage, or receipt. |
get_receipt | Retrieve a public, signed OCD receipt by its exact receipt_id. |
verify_receipt | Check a receipt's proof โ VALID, INVALID, or UNVERIFIABLE. |
This surface cannot send payments, custody funds, authorize a wallet,
reach private operations, or call the paid x402 tools below โ it only
inspects and verifies. No account, API key, or credential of any kind is
needed or accepted.
Live, validated Claude custom connector. Add it in Claude at
Settings/Customize โ Connectors โ Add custom connector, paste
https://mcp.onchaindiligence.com/public/mcp, name it OnChainDiligence,
leave authentication as None (transport is Streamable HTTP). It has been
exercised through a real Claude host loop โ tool discovery, tool selection,
and correct interpretation of VALID/receipt content all confirmed. The same
URL works with any Streamable HTTP MCP client, including ChatGPT's custom
connector setup, using the same steps.
Try it against a real example receipt:
OCD-RCP-NB51-QG4S-VCAN-Y57F.
https://mcp.onchaindiligence.com/mcp โ the paid surface, billed
per-call in USDC on Base via x402. tools/list returns
nine tools today: six priced Evidence-Provider/commerce tools, plus the
same three free tools from section 3 (also available here for convenience).
| Tool | Description | Price |
|---|
preflight_payment | Evaluate a proposed payment against policy; issues a signed PREFLIGHT receipt + finalization capability. | $0.01 |
screen_wallet | Screen a wallet address against the Chainalysis on-chain sanctions oracle (US/EU/UN lists). | $0.01 |
screen_name | Fuzzy-match a person or company against OFAC SDN names and strong aliases. | $0.02 |
verify_uk_company | UK company lookup: status, type, incorporation, registered address, people with significant control. | $0.05 |
verify_us_company | Resolve a public US company through SEC EDGAR. | $0.05 |
diligence | Run wallet and UK-company checks in parallel, without claiming a verified link between them. | $0.05 |
inspect_payment, get_receipt, verify_receipt | Same as section 3 โ free, no payment required, also reachable here. | free |
Payment mechanics (unpaid call โ x402 requirement โ agent policy + wallet
authorization โ paid retry โ signed result) are unchanged from before โ see
ยง How payment works below.
Generic MCP hosts do not necessarily pay x402 challenges automatically. For a
first paid pilot, use the Commerce SDK or direct HTTP/x402 route unless the
chosen MCP host explicitly supports x402 payments.
(This corrects issue #4: the README previously said "five tools" and didn't mention preflight_payment, inspect_payment, get_receipt, or verify_receipt, or that the last three are free.)
5. Commerce SDK
For a TypeScript application (as opposed to an MCP-connected chat agent),
@onchaindiligence/sdk/commerce
orchestrates the full lifecycle in-process โ open โ preflight โ execute โ
observe/finalize โ with the recovery guarantees above built in, rather than
hand-rolling the MCP/x402 sequence:
npm install @onchaindiligence/sdk
import { createCommerceClient, apiPurchasePolicy } from '@onchaindiligence/sdk/commerce'
import { NodeFileRecoveryStore } from '@onchaindiligence/sdk/commerce/node'
const ocd = createCommerceClient({ recovery: new NodeFileRecoveryStore('./ocd-recovery') })
const { policy } = apiPurchasePolicy({ maxAmount: '1.00', allowedNetwork: 'eip155:8453', allowedAsset: BASE_USDC })
const op = await ocd.open({ action: proposedPayment, policy })
const evaluation = await op.preflight()
if (evaluation.kind !== 'ready') return handleThat(evaluation)
const execution = await op.execute({ executor: myExecutor })
const result = await op.observeAndFinalize()
See the SDK repo's README for the full executor list (X402BaseUsdcExecutor,
PayBoxCommerceExecutor, MockCommerceExecutor) and the still-supported
Evidence Provider client (screen, screenName, verifyCompany,
diligence) โ the SDK covers both.
6. Receipts and verification
Every preflight and commerce receipt is a signed, content-addressed
OCD-RCP-XXXX-XXXX-XXXX-XXXX object. Retrieve one for free with get_receipt
(or GET /receipts/:receiptId); check it with verify_receipt (or the
public verifier) to get back
VALID / INVALID / UNVERIFIABLE.
- Online verification (
verify_receipt) is a convenience: it fetches
OCD's own public key registry and trusts this server to have checked
honestly.
- Offline verification is strictly stronger โ run the same check
yourself against the published
@onchaindiligence/agent-evidence
package and your own copy of the key registry.
See section 10 for exactly what VALID does and doesn't mean.
7. Current integrations: ChatGPT and Claude
Both are ordinary Streamable HTTP MCP clients โ no special-casing on this
server's side. Point either at the free /public/mcp endpoint (section 3)
for read-only inspection/verification, or the paid /mcp endpoint (section
4) for the full Evidence-Provider/commerce tool set.
- Claude โ add as a custom connector (see section 3). This has been
validated through a real Claude host loop: correct tool discovery, correct
tool selection, and correct interpretation of receipt content and VALID's
actual scope.
- ChatGPT โ register the same URL as a custom MCP connector; ChatGPT
calls
tools/list and tools/call exactly like any other client.
- Gemini / a custom agent tool loop โ any Streamable HTTP MCP client
works unmodified; see
test/client.ts for the exact
wire format.
Neither integration implies a formal app-store/directory listing beyond what
each platform's own directory pages state independently of this README.
The application layer that decides whether to act on a tool's result is
the real enforcement boundary โ "the model remembered to call OCD" is never
a substitute for that.
8. Evidence Providers
Supporting capabilities the lifecycle (or a caller directly) can draw
evidence from โ not the company's primary description:
- Chainalysis on-chain sanctions oracle โ a free, public smart contract
on Ethereum mainnet (
0x40C57923924B5c5c5455c48D93317139ADDaC8fb), queried
read-only via viem. No Chainalysis API key or
commercial relationship required; it's a public good reflecting US/EU/UN
sanctions lists. The per-call fee covers infrastructure, not the data.
- OFAC SDN name screening โ fuzzy match against primary names and strong
aliases only; weak AKAs are not screened, per OFAC guidance.
- UK Companies House โ official register lookup: status, type,
incorporation, registered office, people with significant control.
- SEC EDGAR โ public US company/fund resolution by ticker, CIK, or name.
These checks use the same underlying public-data sources as the
HTTP API โ separate deployments, so
response-level equivalence is enforced by contract tests, not assumed.
9. Architecture
agent (MCP client + x402 wallet, or Claude/ChatGPT as a custom connector)
โ Streamable HTTP
โผ
index.ts โโโโโโโโโโโโโโโโ Hono app; routes /mcp and /public/mcp
โ
โโโ src/server.ts โโโโโโ paid handler: preflight_payment + 5 Evidence-
โ Provider tools (x402-gated) + the same 3 free
โ tools registered again for convenience
โ
โโโ src/publicMcp.ts โโโ free handler: inspect_payment, get_receipt,
โ verify_receipt only. Never imports or
โ delegates to the paid handler.
โ
โโโ src/preflight.ts โโโโ deterministic policy evaluation
โโโ src/receiptTools.ts โ get_receipt / verify_receipt primitives,
โ shared by both handlers and the free HTTP
โ route (receiptsRoute.ts)
โโโ src/chainalysis.ts โโ sanctions oracle read (viem, Ethereum mainnet)
โโโ src/companiesHouse.ts โ UK Companies House lookup
10. Security / claim limitations
- VALID means cryptographic integrity and authenticity of the receipt
under the verifier contract โ not universal truth of every claim inside
it, and not proof the underlying action succeeded.
- An OCD
ALLOW is a policy comparison, not wallet authorization. Your
own wallet/provider always makes the actual authorization decision.
- Settlement does not prove service/merchant delivery. OCD independently
observes that value moved; it does not independently verify that whatever
was purchased was actually delivered.
- Caller-reported merchant evidence stays labeled as caller-reported โ
it is never silently upgraded to independently-observed evidence.
- OCD is not a fraud detector and not a compliance guarantee. Its
checks are evidence-based tooling; using it does not by itself satisfy any
specific law, regulation, or compliance regime.
- OCD does not claim a partnership, endorsement, or affiliation with any
executor, wallet provider, or platform beyond what that party has stated
independently.
- UNKNOWN and UNVERIFIED are preserved, never quietly resolved. A
receipt that can't confirm something says so rather than defaulting to a
clean-looking result.
Found a vulnerability? Report it to security@onchaindiligence.com. See
onchaindiligence.com/.well-known/security.txt.
How payment works
Payment rides on x402, the open agent-payment standard
built on HTTP 402 Payment Required:
- The agent calls a tool with no payment attached.
- The server returns the payment requirements (amount, asset, recipient, network).
- The agent signs a USDC payment authorization from its own wallet.
- The agent retries the call with the payment in the tool-call
_meta.
- The server verifies and settles via the Coinbase facilitator, runs the check, and returns the result.
The flow is non-custodial: USDC moves directly from the agent's wallet to
the recipient. This server never holds funds and runs no billing system โ
deliberate, given the product is about not being a trusted intermediary.
const client = await connectMcp('https://mcp.onchaindiligence.com/mcp')
const { tools } = await client.listTools()
const unpaid = await client.callTool({
name: 'screen_wallet',
arguments: { address: '0x0000000000000000000000000000000000000000' },
})
const requirement = unpaid.structuredContent.accepts[0]
const payment = await createPaymentHeader(agentWallet, 1, requirement)
const paid = await client.callTool({
name: 'screen_wallet',
arguments: { address: '0x0000000000000000000000000000000000000000' },
_meta: { 'x402/payment': payment },
})
The runnable test/client.ts performs that exact
sequence with MCP_SERVER_URL and PAYER_PRIVATE_KEY environment-variable
placeholders; it never embeds a wallet key in source. Always read the current
price from the unpaid response rather than hard-coding it.
Two payment rails by design
OnChainDiligence settles two ways, because the agent-payment landscape is
split between two standards:
| HTTP API | MCP server (this repo) |
|---|
| Protocol | Machine Payments Protocol (Stripe/Tempo) | x402 (Coinbase/Base) |
| Chain | Tempo | Base mainnet |
| Currency | pathUSD | USDC |
| Settlement | session-based | per-call, on-chain |
Same checks, same signed results, different rails for different ecosystems.
Standard HTTP x402 surface
Alongside the MCP transport, every Evidence Provider check is also available
to a generic x402 buyer over plain HTTPS, using the x402 v2 stack
(CAIP-2 networks, HTTP 402, X-PAYMENT header):
| Resource | Price |
|---|
GET /x402/screen/:address | $0.01 |
GET /x402/screen-name?name= | $0.02 |
GET /x402/uk-company/:companyNumber | $0.05 |
GET /x402/us-company?q= | $0.05 |
GET /x402/diligence?wallet=&company= | $0.05 |
GET /x402/verdict/:address | $0.01 |
Free discovery documents: /openapi.json
and /.well-known/x402.
Buyer walkthrough: docs/X402_HTTP_BUYERS.md.
Why the MCP rail is still on x402 v1, and what migrating it would require:
docs/MCP_X402_MIGRATION.md.
Design notes
A few decisions worth explaining, since they reflect real constraints rather
than preference:
- Why Base and not Tempo. The HTTP API settles on Tempo, so unifying on
one chain would have been cleaner. But the
x402-mcp package hardcodes its
network type to "base" | "base-sepolia" โ Tempo is not a permitted value.
Rather than fork the package or write a custom facilitator, this server
settles on Base, and OnChainDiligence accepts two rails. The constraint is
documented, not papered over.
- The test client is hand-rolled.
x402-mcp ships a withPayment
helper, but it imports an MCP client API (experimental_MCPClient) that
the ai SDK removed in v5. Rather than pin an old ai version,
test/client.ts performs the x402 loop directly on the MCP SDK plus
x402/client. The server itself doesn't depend on ai, so this is a
test-only concern.
- Public-data clients are currently duplicated.
chainalysis.ts and
companiesHouse.ts began as copies of the HTTP API implementations. They
can drift, so the remediation roadmap moves them behind a shared
service/package and adds contract tests.
Running locally
Requires Node 22+.
npm install
cp .env.example .env
npm run dev
Environment variables:
| Variable | Purpose |
|---|
COMPANIES_HOUSE_API_KEY | UK Companies House API key (free). |
SANCTIONS_ORACLE_RPC_URL | Ethereum RPC for the oracle read. |
X402_RECIPIENT_ADDRESS | Base address that receives USDC. |
X402_NETWORK | base-sepolia (testnet) or base (mainnet). |
CDP_API_KEY_ID / CDP_API_KEY_SECRET | Coinbase Developer Platform keys for the x402 facilitator. |
ATTESTATION_SERVICE_TOKEN | Server-to-server credential for the API's internal attestation service. Required for signed results; never expose it to browser code. |
To exercise the full paid loop against the running server:
License
MIT โ see LICENSE.