About Server
Server is an MCP server published by winsznx in the Blockchain category: unified payment execution layer for Stellar x402, MPP charge, MPP session behind one client.pay() call.
The repository has 13 stars and 76 forks, with the last commit 3 days ago. Recent commit activity is the strongest signal that reported issues will get attention.
Install
git clone https://github.com/winsznx/routedockThis server has no ConduID identity, so agent calls to it are not receipted. Pin the version you install and review the source before granting it credentials.
Ask AI
Ask AI about Server
Powered by Claude · Grounded in docs
Security checks
Static checks derived from the repository 2 days ago. Heuristics on the source, not an audit.
- ✓README presentThe repository ships documentation.
- ✓License declaredUsable under a stated license.
- ✓Tests presentA test suite exists in the repository.
- ✓Dependencies pinnedA lockfile pins dependency versions.
- ✓No dynamic code executionSource scan found no eval, dynamic Function, or shell execution.
1 check has not been run yet.
Releases
README
RouteDock
Unified payment execution layer for autonomous agents on Stellar
The Problem
Three payment protocols exist on Stellar for agent-to-service transactions: x402 (Coinbase), MPP charge (Stripe/Stellar), and MPP session channels (stellar-experimental). Each has a separate SDK, a separate integration path, and no discovery mechanism. The one-way-channel Soroban contract is unaudited and has no safe integration path. Every agent team hardcodes payment logic per endpoint.
The Solution
import { RouteDockClient } from '@routedock/routedock'
const client = new RouteDockClient({ wallet, network: 'testnet' })
const result = await client.pay('https://provider.example.com/price')
// result.mode → 'x402' | 'mpp-charge' | 'mpp-session' | 'mpp-session-ws' (selected automatically)
One SDK. One function call. The mode is selected from the provider's routedock.json manifest. The agent writes nothing else.
Architecture
graph LR
Agent --> ModeRouter
ModeRouter --> x402Client
ModeRouter --> MppChargeClient
ModeRouter --> MppSessionClient
x402Client -->|mainnet| OZFacilitator["OZ Facilitator"]
x402Client -->|testnet| LocalFacilitator["Local Facilitator"]
OZFacilitator --> Stellar
LocalFacilitator --> Stellar
MppChargeClient --> StellarSAC["Stellar SAC transfer"]
StellarSAC --> Stellar
MppSessionClient --> ChannelContract["one-way-channel\nSoroban contract"]
ChannelContract --> Stellar
x402Client --> ProviderA["Provider A\n/price"]
MppChargeClient --> ProviderA
MppSessionClient --> ProviderB["Provider B\n/stream/orderbook"]
Security Architecture
| Layer | Mechanism | Enforcement Point |
|---|---|---|
| Application | per-voucher challenge guard (channel, amount, cumulative) | packages/sdk/src/client/MppSessionClient.ts:reserveNextCumulative |
| Application | manifest schema validation (AJV draft-07) | packages/sdk/src/client/ModeRouter.ts |
| Database | monotonic cumulative trigger | supabase/migrations/001_init.sql:37,50 |
| Database | RLS on sessions table | supabase/migrations/001_init.sql:128-131 |
| Contract | daily USDC cap policy | contracts/agent-vault/src/lib.rs:__check_auth |
| Contract | endpoint allowlist policy | contracts/agent-vault/src/lib.rs:__check_auth |
| Contract | session key expiry | contracts/agent-vault/src/lib.rs:__check_auth |
| Contract | 17,280-ledger Wasm upgrade notice period | contracts/agent-vault/src/lib.rs:propose_upgrade / execute_upgrade |
| Contract | one-way-channel signature verification | CCK4XOW3YKQUEZFONUTINKMSNW7SNMRQZURME5U3UP7E6WNGK7UHUCAH |
Security Notice
The one-way-channel Soroban contract (stellar-experimental/one-way-channel) has NOT been audited. RouteDock wraps it with safe defaults (17280-ledger refund window, durable session store with monotonic invariant, DB-level trigger enforcement). Production mainnet use should await a formal audit.
Audit Status:
- Shortlisted auditors: OtterSec, Hacken, Trail of Bits
- SCF Audit Bank application: Submitted
The vault's single admin can still rotate agent keys and change caps, allowlists, and expiry. The upgrade timelock guarantees advance notice before the contract enforcement code itself is replaced; it does not make the admin trustless. Operators and governed payers should monitor upgrade_proposed and upgrade_cancelled, review every target Wasm hash, and use pending_upgrade to display the exact earliest execution ledger.
Soroban Events
The agent-vault contract emits structured events that indexers and Stellar Expert can attest to without parsing tx state changes.
| Event | Topics | Data | When |
|---|---|---|---|
payment_authorized |
(Symbol, payer: Address, payee: Address) |
(amount: i128, asset: Address, daily_cumulative: i128) |
Each successful auth pass in __check_auth |
session_settled |
(Symbol, channel_id: Address, payee: Address) |
(payer: Address, cumulative_amount: i128, voucher_count: u32) |
After channel close, the provider calls record_session_settlement, authorized by its own allowlisted payee key |
upgrade_proposed |
(Symbol) |
(new_wasm_hash: BytesN<32>, ready_at_ledger: u32) |
Admin schedules a Wasm change and starts the notice period |
upgrade_cancelled |
(Symbol) |
(new_wasm_hash: BytesN<32>, ready_at_ledger: u32) |
Admin cancels a scheduled Wasm change |
upgraded |
(Symbol) |
(new_wasm_hash: BytesN<32>) |
A ready Wasm proposal executes successfully |
stellar events --network testnet --start-ledger <LEDGER> --contract-id <VAULT_ID>
Live Testnet Transactions
All produced by a single autonomous agent run against two live provider services. No mocks.
| Type | Tx Hash | Explorer |
|---|---|---|
| x402 settlement | 5f603387807faacdc02c71efb74b26091b1be67740f74dfd581d23d643e2db64 |
view |
| Channel open (deploy) | 6ceba32ba2cfd7f3145090c2e6f741db65ae4e4116f3204f2c3173b5266b98ff |
view |
| Channel close (50 vouchers settled) | 234dcbb34cfb7a086f17474f57cacaa9edee8bc8dee873e8f2b851abc0a29a20 |
view |
| Policy rejection | NO TX — daily cap enforced locally before any broadcast | — |
50 interactions. 2 on-chain transactions. The channel close settled the cumulative amount for all 50 vouchers in a single Soroban invocation.
Contracts deployed on testnet:
- Agent vault:
CAX5IDLC2XHGQSEA2YN3LPLZ7EXLMRXYX3HFJGKFXS6B7OQXBKWO44LT - One-way channel:
CCK4XOW3YKQUEZFONUTINKMSNW7SNMRQZURME5U3UP7E6WNGK7UHUCAH
Install
npm install @routedock/routedock
Quickstart
git clone https://github.com/winsznx/routedock && cd routedock
pnpm install
pnpm --filter @routedock/nulth-sdk build
pnpm --filter @routedock/routedock build
cp apps/provider-a/.dev.vars.example apps/provider-a/.dev.vars
# fill in a throwaway testnet key
pnpm --filter provider-a dev
The build-order requirement (SDK builds before provider dev) is documented in
CONTRIBUTING.md.
Full demo (both providers + agent): see docs/AGENT_RUN_CHECKLIST.md.
Mainnet rollout: see docs/MAINNET_DEPLOYMENT.md.
Redeploying provider-a/provider-b: read docs/PROVIDER_REDEPLOY_ORDERING.md first — a partial redeploy against the current npm SDK version breaks every live client.
Examples
| Example | What it shows |
|---|---|
price-oracle-agent |
Fetches paid price quotes with one-shot x402 settlements. |
inference-agent |
Runs a mock inference provider and pays each response with MPP charge. |
agent-to-agent |
Has an orchestrator agent pay a specialist agent for each summary. |
streaming-orderbook-agent |
Opens an MPP session, consumes 100 voucher-backed orderbook updates, and settles the channel on close. |
From a fresh clone, build the SDKs before starting any example:
pnpm install
pnpm --filter @routedock/nulth-sdk build
pnpm --filter @routedock/routedock build
cd examples/<name>
cp .env.example .env
# fill in .env
pnpm start
Three Payment Modes
x402 — Pay per request
Server returns HTTP 402. Agent signs a Soroban auth entry for a USDC SAC transfer. On mainnet, the OpenZeppelin facilitator verifies and broadcasts. On testnet, the provider runs a local facilitator (same x402 V2 protocol). One request, one settlement.
MPP Charge — Pay per action
Agent sends a payment intent via the Stellar MPP charge protocol. USDC transfers natively via the SAC — no facilitator, lower fees. Server verifies and returns the response.
MPP Session — Pay per time
Agent deposits USDC into a stellar-experimental/one-way-channel Soroban contract. For each unit of data consumed, the agent signs an off-chain ed25519 commitment (no RPC call, no transaction fee). The channel settles with one on-chain close transaction for the cumulative amount.
Dispute Resolution
If a server crashes mid-session, the agent can reclaim deposited funds using the dispute resolution API. Three methods handle the recovery flow:
session.requestRefund()— initiates the refund process on the channel contract, starting the refund window (default 17,280 ledgers ≈24h)session.settleWithLatestVoucher()— server-side counter-mechanism to settle the cumulative amount before the refund window expires, using the highest signed vouchersession.getDisputeStatus()— returns the channel state:'open','in-refund-window','refundable', or'settled'
Raises: RouteDockDisputeError, RouteDockChannelStateError, RouteDockRefundWindowError
Mode Selection
Deterministic, manifest-driven:
- Sustained access requested + a session mode available → session
(
mpp-session-wswhen the caller asks for a WebSocket transport and the provider advertises it, otherwisempp-session) mpp-chargeavailable → charge (lower fees, no facilitator)x402available → x402 (facilitator-backed)- Nothing available → throw
mpp-session-ws — WebSocket streaming sessions
Open a channel, negotiate the voucher, then upgrade the HTTP connection to WebSocket — the transport OpenAI/Anthropic/Google-style inference providers speak natively, without an SSE wrapper:
const session = await client.openSession('https://provider.example.com/stream', {
mode: 'mpp-session-ws',
})
for await (const chunk of session.stream()) {
// each WebSocket frame, JSON-decoded
}
await session.close()
Discovery: routedock.json
Every provider serves /.well-known/routedock.json. The SDK fetches and validates it (JSON Schema, AJV) before every call. Agents never hardcode payment logic.
{
"routedock": "1.0",
"name": "Stellar DEX Price Feed",
"modes": ["x402", "mpp-charge"],
"network": "testnet",
"asset": "USDC",
"asset_contract": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA",
"assets": [
{
"asset": "USDC",
"asset_contract": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA",
"modes": ["x402"]
},
{
"asset": "XLM",
"asset_contract": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
"modes": ["mpp-charge"]
}
],
"payee": "G...",
"pricing": {
"x402": { "amount": "0.001", "per": "request" },
"mpp-charge": { "amount": "0.0008", "per": "request" }
},
"endpoints": { "price": "GET /price" },
"tags": ["price", "stellar", "dex", "orderbook"]
}
Manifests support optional multi-asset scoping via assets while preserving root asset / asset_contract for backward compatibility. See Multi-Asset Support for full details on asset normalization, endpoint-aware selection, and client preflight.
Compatibility Notice: Because the manifest schema uses
additionalProperties: false, clients older than the multi-asset release will reject manifests containing the newassetsfield. Providers must not emitassetsuntil clients have upgraded.
The Supabase providers table indexes manifests with pg_trgm trigram search — agents query by capability, not by URL.
Provider Integration
Express
import { routedock } from '@routedock/routedock/provider'
app.use('/price', routedock({
modes: ['x402', 'mpp-charge'],
pricing: { x402: '0.001', 'mpp-charge': '0.0008' },
asset: 'USDC',
assetContract: process.env.USDC_ASSET_CONTRACT,
payee: process.env.STELLAR_PAYEE_ADDRESS,
payeeSecretKey: process.env.STELLAR_PAYEE_SECRET,
network: process.env.STELLAR_NETWORK,
facilitatorApiKey: process.env.OPENZEPPELIN_API_KEY, // mainnet only
manifest,
}))
Hono (Cloudflare Workers, Bun, Deno Deploy)
import { Hono } from 'hono'
import { routedockHono } from '@routedock/sdk/provider/hono'
const app = new Hono()
app.use('/price', routedockHono({
modes: ['x402', 'mpp-charge'],
pricing: { x402: '0.001', 'mpp-charge': '0.0008' },
asset: 'USDC',
assetContract: process.env.USDC_ASSET_CONTRACT,
payee: process.env.STELLAR_PAYEE_ADDRESS,
payeeSecretKey: process.env.STELLAR_PAYEE_SECRET,
network: process.env.STELLAR_NETWORK,
facilitatorApiKey: process.env.OPENZEPPELIN_API_KEY, // mainnet only
manifest,
}))
export default app
One middleware. Handles x402, MPP charge, and MPP session. Serves routedock.json. Verifies payments. Settles on-chain.
This example uses in-memory defaults for settlement idempotency and session
state, which aren't safe once requests can land on different isolates or
processes (Cloudflare Workers, Deno Deploy, or any multi-instance deployment).
See Running a provider in production
for the durable stores, cron reconciliation, and mpp-session-ws upgrade
route a serverless provider needs.
Testing your settlement callbacks
Provider authors wiring onSettled (e.g. a Supabase write) shouldn't have to mock the whole middleware chain or sign real payments to test that callback. @routedock/routedock/testing is the msw-equivalent for RouteDock providers: a mock middleware that drives your callbacks with synthetic data.
import express from 'express'
import request from 'supertest'
import { createMockRoutedockMiddleware } from '@routedock/routedock/testing'
const onSettled = vi.fn() // your real Supabase-writing callback under test
const app = express()
app.use('/price', createMockRoutedockMiddleware({ mode: 'x402', payment: 'auto-pass', onSettled }))
app.get('/price', (_req, res) => res.json({ price: '42' }))
await request(app).get('/price').expect(200)
expect(onSettled).toHaveBeenCalledWith(
expect.any(String),
'0.001',
'x402',
expect.any(String), // payer
)
payment: 'auto-pass'(default) invokes the callbacks with synthetic data, then runs your route handler.'auto-fail'responds402and skips both — exactly like a rejected payment.mode: 'mpp-session'andmode: 'mpp-session-ws'both drive the fullonSessionOpen → onVoucher* → onSettledsequence;onSettledreports the transport it ran.- The callbacks receive the same arguments as the real adapter, including
payer(a StellarG...account by default, ornull). - Override synthetic values via
synthetic: { txHash, amount, channelId, rate, voucherCount, payer }. - To test a callback with no HTTP server at all, call
runMockSettlement(opts)directly — it returns the synthetic settlement record.
Monorepo Structure
routedock/
├── packages/sdk/ # @routedock/routedock — npm
├── packages/mcp-server/ # @routedock/mcp-server — MCP server for LLM agents
├── apps/web/ # Next.js 16 dashboard + landing — Cloudflare Workers
├── apps/provider-a/ # Cloudflare Worker price endpoint (x402 + MPP charge)
├── apps/provider-b/ # Cloudflare Worker orderbook endpoint (MPP session)
├── contracts/agent-vault/ # Soroban contract account — Stellar
├── agent/ # Reference autonomous agent
└── supabase/ # Schema + RLS + trigram indexes + Realtime
Capabilities
| Capability | Detail |
|---|---|
| x402 settlement (testnet) | Local ExactStellarFacilitatorScheme — no third-party dependency |
| x402 settlement (mainnet) | OZ hosted facilitator at channels.openzeppelin.com/x402 with Bearer auth |
| MPP charge settlement | Server-side broadcast via @stellar/mpp pull mode |
| MPP session: off-chain vouchers | 50 vouchers verified — each signed as ed25519 commitment, no on-chain tx per voucher |
| MPP session: on-chain close | Single Soroban close(amount, signature) settles the cumulative amount |
| Contract account policy enforcement | __check_auth daily cap rejects overspend at the Soroban level |
| Dashboard Realtime | Supabase postgres_changes subscriptions on sessions and tx_log |
| Discovery registry | providers table with pg_trgm trigram indexes for fuzzy capability search |
| npm package | @routedock/routedock@0.1.0 |
| MCP server | @routedock/mcp-server — LLM agent integration via Model Context Protocol |
| Network support | `STELLAR_NETWORK=testnet |
Deployed Services
| Service | URL | Status |
|---|---|---|
| npm package | @routedock/routedock |
published |
| Agent vault | CAX5IDLC2XHGQSEA2YN3LPLZ7EXLMRXYX3HFJGKFXS6B7OQXBKWO44LT |
live (testnet) |
| Channel contract | CCK4XOW3YKQUEZFONUTINKMSNW7SNMRQZURME5U3UP7E6WNGK7UHUCAH |
live (testnet) |
| Dashboard | routedock.xyz | live |
| Provider A (price endpoint) | api-a.routedock.xyz | live |
| Provider B (orderbook endpoint) | api-b.routedock.xyz | live |
Full Technical Brief
For a detailed walkthrough of the architecture, protocol conformance, security model, and design decisions, see the Submission Brief.
What's next
RouteDock is a chain-agnostic agent payment protocol with Stellar as its canonical home. The protocols it unifies aren't Stellar-bound — x402, which RouteDock wraps, was designed multi-chain and already settles on EVM.
The Multi-Chain Roadmap sketches a ChainAdapter interface with the existing Stellar clients as the reference implementation and EVM (via x402) as the first extension target — keeping the single-call agent experience (client.pay(url)) identical across chains. The plan is additive: the manifest's chain field is optional and defaults to stellar, so every existing provider and agent keeps working.
License
MIT
README fetched from the repository 2 days ago. The original is authoritative.