# HyperMove > Make any web3 dApp agent-callable and monetizable per call. One MCP endpoint lets AI agents discover, connect to, and pay for on-chain actions across 27+ chains. Open-source, MIT. > MCP endpoint: https://hypermove.duckdns.org/api/mcp · Skill catalog: https://hypermove.duckdns.org/api/skills · Manifest: https://hypermove.duckdns.org/.well-known/webmcp.json ## Docs - [Introduction](https://hypermove.duckdns.org/docs) - [Quickstart — 5 min](https://hypermove.duckdns.org/docs/quickstart) - [MCP Gateway](https://hypermove.duckdns.org/docs/mcp-gateway) - [Dream Cycle — offline memory](https://hypermove.duckdns.org/docs/dream-cycle) - [LLM Service — model backend](https://hypermove.duckdns.org/docs/llm-service) - [n-payment SDK](https://hypermove.duckdns.org/docs/n-payment) --- # Introduction > **HyperMove makes any web3 dApp agent-callable — and monetizable per call.** > One MCP endpoint lets AI agents discover, connect to, and pay for on-chain > actions across 27+ chains. Open-source, MIT, built on [n-payment](/docs/n-payment). _Agents: read all of these docs as one plain-text document at [`/llms.txt`](/llms.txt)._ ## What it is AI agents can reason, but they can't safely *act* on web3 without a unified, paid, guard-railed connection. HyperMove is that connection. It exposes three surfaces: - **MCP Gateway** (`https://hypermove.duckdns.org/api/mcp`) — one endpoint where an agent searches a unified cross-chain catalog, reads live data (EVM · Stellar · XRPL), and pays per query. See [MCP Gateway](/docs/mcp-gateway). - **Tools & skills** — harness-wrapped agent-skills you install into any MCP client in one paste; each runs inside observability + policy + output-enforcement. Browse them at [/tools](/tools). - **WebMCP client** — 3 lines of HTML turn any dApp's forms and buttons into agent-callable tools, monetized with an x402-USDC paywall. ## How it works 1. An agent connects to the gateway and gets a bearer key (wallet signature or email). 2. It discovers capabilities (`search`, `data.call`, `skill.*`) over MCP. 3. When it calls a paid tool, HyperMove returns an HTTP 402 challenge; the agent settles in USDC via [n-payment](/docs/n-payment) and the call completes. 4. Every call runs inside the harness — errors captured, policy enforced, output verified. ## How to use it Pick the path that matches your goal: | I want to… | Start here | |---|---| | **Let my agent call web3** | [Connect your agent](/mcp-connect) → then the [MCP Gateway](/docs/mcp-gateway) guide | | **Give my agent memory across sessions** | [Dream Cycle](/docs/dream-cycle) — log episodes, consolidate offline, query cheap | | **Get a key with no wallet/browser** | [Get a key — no wallet needed](/docs/agent-auth) — terminal-only, for headless agents | | **Install a ready-made skill** | Browse [/tools](/tools), copy one install prompt, paste into your agent | | **Monetize my own dApp or API** | [Quickstart — 5 min](/docs/quickstart) + the [n-payment SDK](/docs/n-payment) | | **Self-host or configure the model backend** | [LLM Service](/docs/llm-service) — the standalone process behind `/scan` and Dream Cycle extraction | ## Next - [Quickstart — 5 min](/docs/quickstart) — a running paywall + an agent that pays $0.01. - [MCP Gateway](/docs/mcp-gateway) — connect, search, pull news, pay per query. - [Dream Cycle](/docs/dream-cycle) — give your agent memory across sessions, near-zero cost. - [LLM Service](/docs/llm-service) — the standalone model backend behind `/scan` and Dream Cycle extraction. - [n-payment SDK](/docs/n-payment) — `fetchWithPayment()`, `createPaywall()`, 27 chains · 14 protocols. --- # Quickstart — 5 min > Goal: a running paywall and an agent that pays $0.01 USDC to call it. > Built on [n-payment@0.29.1](https://www.npmjs.com/package/n-payment) — single peer dep on `viem`. Open-source · MIT. ## Step 1 — Install (20 sec) ```bash mkdir my-paid-agent && cd my-paid-agent npm init -y npm install n-payment viem hono ``` ## Step 2 — Provider: paywall (90 sec) ```ts // server.ts import { createPaywall } from 'n-payment/middleware'; import { Hono } from 'hono'; const app = new Hono(); app.use('*', createPaywall({ payTo: process.env.PAY_TO as `0x${string}`, chain: 'goat-mainnet', asset: 'USDC', routes: { '/api/forecast': { priceMicroUsdc: 10_000n }, // $0.01 }, })); app.get('/api/forecast', (c) => c.json({ city: 'Hanoi', temp: 31 })); export default app; ``` Verify the 402 contract: ```bash curl -i http://localhost:3000/api/forecast # → HTTP/1.1 402 Payment Required # → WWW-Authenticate: x402-USDC realm="…", price="10000", chain="goat-mainnet" ``` ## Step 3 — Consumer: pay (60 sec) ```ts // agent.ts import { createPaymentClient } from 'n-payment'; const client = createPaymentClient({ chains: ['goat-mainnet'], ows: { wallet: 'my-agent' }, policy: { maxPerTransaction: 100_000n }, }); const res = await client.fetchWithPayment('http://localhost:3000/api/forecast'); console.log(res.status, await res.json()); // → 200 { city: 'Hanoi', temp: 31 } ``` The SDK handles the 402 → sign → retry round-trip in one call. Keys never leave the OWS vault. ## Step 4 — Paid MCP server (60 sec) ```ts // paid-mcp.ts import { createPaidMcpServer, paidTool } from 'n-payment/agent'; const server = createPaidMcpServer({ name: 'MyAgentService', payTo: '0xYourAddress', chain: 'goat-mainnet', tools: [ paidTool({ name: 'forecast', description: 'Get weather forecast', price: 10_000n, // $0.01 USDC handler: async ({ city }) => ({ city, temp: 22 }), }), ], }); await server.listen(3000); ``` ## You're done - ✅ Real `HTTP 402` paywall via `n-payment/middleware` - ✅ `fetchWithPayment()` that pays $0.01 USDC - ✅ Vault-bound signing — your agent never touches a private key - ✅ 27 chains · 14 protocols — see [n-payment docs](/docs/n-payment) --- # MCP Gateway v4.0 + v2.1 Guardians > One endpoint — `https://hypermove.duckdns.org/api/mcp` — makes cross-chain web3 agent-callable. > **40 tools** today (verified live via `/api/mcp/health`): search + catalog discovery, > daily news + AI insight, tiered multi-chain payment, XRPL/Flare/GOAT builder briefs and > deep reads, confidential compute, and Dream Cycle — an offline memory-consolidation > pipeline agents use to learn from their own episode logs. WorkOS or wallet sign-in, 5 > free queries / 24h, then metered `$0.001–$0.10` via x402/MPP. As of 2026-08-01, every > tool call also passes through **Gateway Guardians** (deterministic cost caps + circuit > breaker + prompt-injection defense) — enforcement lives in code, not in a prompt. The whole gateway lives behind `FEATURE_HYPERMOVE_MCP_GATEWAY_V1`. When off, `/api/mcp` serves the legacy 2-tool surface unchanged (60-second rollback). Every capability below ships behind its own additional sub-flag, documented inline — flip any one off without touching the others. ## Tools (40, grouped by purpose) ### Discovery — always on | Tool | Tier | Purpose | |---|---|---| | `search` | T1 `$0.001` | Hybrid lexical + vector search over the cross-chain catalog | | `codemode.vector.search` | T3 `$0.10` | Pure semantic search | | `codemode.spec` | T1 | OpenAPI-3.1-style super spec for every enabled tool | | `codemode.catalog` | T1 | Full catalog manifest, flat — grep-friendly for agents | | `codemode.describe` | T1 | Detail-on-demand for one catalog entry id | | `codemode.payments.networks` | T1 | List supported networks × rails × assets before paying | | `xrpl.toolkit.list` | T1 | Canonical SDK/CLI/facilitator directory for XRPL agentic payments | ### Payments (n-payment, x402/MPP) | Tool | Tier | Purpose | |---|---|---| | `payments.settle` | unmetered | Settle via x402/MPP proof to unlock a 100-query paid session | | `payments.status` | unmetered | Check the active paid session's remaining quota | ### Live cross-chain reads | Tool | Tier | Purpose | |---|---|---| | `data.call` | T2 `$0.01` | Canonical read (EVM + Stellar + XRPL) via the best provider, auto-fallback | ### News + agentic synthesis — `FEATURE_MCP_NEWS_V1` / `FEATURE_MCP_AGENTIC_V1` | Tool | Tier | Purpose | |---|---|---| | `news.search` | T1 | Search daily web3 news across tracked projects | | `codemode.news.digest` | T2 `$0.01` | Per-project daily rollup | | `codemode.news.insight` | T3 `$0.10` | AI-synthesized insight for one project | | `insight.roadmap` | T3 | Product-upgrade roadmap synthesized from today's news + catalog | | `ideas.generate` | T3 | Grounded product/feature ideas tied to a real gateway capability | | `skillify` | T2 | Codify a described task into a reusable skill spec | ### Agent-skills discovery — `FEATURE_HYPERMOVE_TOOLS` | Tool | Tier | Purpose | |---|---|---| | `skills.list` | T1 | Browse the self-contained agent-skill catalog | | `skills.install` | T1 | Get the install instruction + full SKILL.md for one skill | | `skills.install_prompt` | T1 | Copy-paste install prompt only, optionally host-tightened | Skills **install and run in your own workspace** — the gateway is not their execution host. See "Agent-skills" below. ### Builder briefs — `FEATURE_MCP_BUILDER_BRIEF` | Tool | Tier | Purpose | |---|---|---| | `flare.builder.brief` | T3 | FTSO, FAssets, FDC, FCC capabilities + corpus + news | | `xrpl.builder.brief` | T3 | MPT, vault, lending, amendments + corpus + news | | `goat.builder.brief` | T3 | BTC-native settlement, lending, MPP + corpus + news | ### XRPL deepening — `FEATURE_MCP_XRPL_V3` | Tool | Tier | Purpose | |---|---|---| | `xrpl.settlement.quote` | T2 | RLUSD vs native-XRP cost/finality comparison | | `xrpl.x402.status` | T1 | T54 x402 facilitator health + trustline status | | `xrpl.vault.info` | T1 | XLS-65 vault state — gated on the amendment being live | | `xrpl.lending.status` | T1 | XLS-66 lending state — gated on the amendment being live | | `xrpl.yield.compare` | T2 | Compare XRP/RLUSD yield venues, source-labeled | | `xrpl.hub.trending` | T3 | XRPL AI Hub agentic-payments index + amendment vote status | `xrpl.vault.info` / `xrpl.lending.status` never return a raw RPC error while XLS-65/66 is still mid-vote — they return a structured `{ok:false, reason:'amendment_not_active'}` instead, so an agent can branch on it deterministically. ### Flare — `FEATURE_MCP_FLARE_V1` | Tool | Tier | Purpose | |---|---|---| | `flare.fassets.bridgeStatus` | T1 | FXRP bridge lifecycle + adoption stats | ### Confidential compute — `FEATURE_MCP_CONFIDENTIAL_V1` | Tool | Tier | Purpose | |---|---|---| | `confidential.attest` | T2 | Verify a TEE remote-attestation quote (real check, never mocked) | | `flare.confidential.swap` | `confidential` tier | Confidential swap via FCC/PMW — honest `fcc_not_live` refusal until FCC ships | | `flare.confidential.status` | T1 | Pre-check whether FCC is live on a given network | ### Flare Compute Extension + Token Profiles — `FEATURE_MCP_INSTRUCT_V1` / `FEATURE_MCP_TOKEN_PROFILE_V1` | Tool | Tier | Purpose | |---|---|---| | `flare.instruct.dispatch` | T2 | Submit an instruction to the Flare Compute Extension | | `flare.token.save` | T2 | Compute + persist a structured Token Profile (FLR/WFLR/FXRP/FBTC/FDOGE) | | `flare.token.profile` | T1 | Retrieve a saved (or freshly computed) Token Profile | `flare.token.save` is verified end-to-end (see Gateway Guardians below) — its own handler output is checked before it ships. ### Dream Cycle — offline memory consolidation — `FEATURE_MCP_DREAM_CYCLE` | Tool | Tier | Purpose | |---|---|---| | `submit_episode_log` | unmetered | Batch-upload episode logs to cold storage (zero LLM calls) | | `start_dream` | dream paid tier | Run the pipeline (preprocess → cluster → extract → consolidate → prune) | | `get_dream_config` | unmetered | Retrieve the last stored Dream Cycle config for an agent | | `query_dream` | unmetered | Query consolidated memories by natural-language query | | `get_dream_stats` | unmetered | Last-run metadata: status, memories added/removed, budget used | Dream reads and ingestion are unmetered. `start_dream` requires a Dream-tier payment whenever MCP auth and the paywall are enabled; its per-cycle `budget_usd` remains an independent cost guardrail. When `FEATURE_MCP_DREAM_PAYMENT_BINDING=true`, first call `start_dream` without payment to receive a quote. Submit the quoted RLUSD payment with its nonce memo, then retry the same call with `X-Payment-Quote-Id`, `X-Payment`, `X-Payment-Chain`, and `X-Payment-Asset`. The quote is bound to the authenticated user and `agent_id`. guardrail, not the gateway's free-tier metering. See "Dream Cycle" below for the full learn-loop walkthrough. ## Gateway Guardians — deterministic enforcement (2026-08-01) Every tool call above now passes through two code-level checks before and after dispatch — not prompt instructions an LLM could ignore, but the same `sentinel.ts` + `output-enforcer.ts` modules the platform-layer observability stack already used, now wired directly into `/api/mcp`'s dispatch path: ```bash FEATURE_MCP_GUARDIANS=true # default — sentinel pre-call check + record, per-tool verify FEATURE_MCP_GUARDIANS=false # opt-out — byte-identical to the pre-2026-08-01 gateway ``` **Pre-call**: cost caps (per-agent daily/hourly USD), a circuit breaker (opens after a sliding-window error-rate threshold), an optional endpoint allowlist, and a prompt-injection heuristic scan the call arguments. A blocked call never reaches the tool handler and returns: ```jsonc { "error": { "code": -32000, "message": "blocked by guardian policy", "data": { "policy": "cost_cap", "reason": "daily_cap_exceeded" } } } ``` **Post-call (opt-in per tool)**: a handler's own output can be checked against a declared contract (schema / nonempty / JSON-serializable / math) before the result ships to the caller. Most tools declare nothing and are unaffected; `flare.token.save` is the one tool wired today as a live example — its response envelope's `ok` field is verified present before the caller ever sees it. This is **independent of `FEATURE_HM_PLATFORM`** (the broader observability/sentinel layer used elsewhere in the app, off by default) — `FEATURE_MCP_GUARDIANS` alone controls whether `/api/mcp` enforces, so turning MCP guardrails on does not require opting into the whole platform-observability stack. Admin sessions bypass the check the same way they bypass metering. Full detail: [`docs/observability.md`](https://github.com/phamdat721101/hypermove-app/blob/main/docs/observability.md#mcp-gateway-guardians) in the repo. ## Dream Cycle — how an agent learns across sessions Dream Cycle turns an agent's own past episode logs into small, durable, retrievable memories — without an LLM in the read path and at near-zero cost: ```bash # 1 — log what happened (zero LLM calls, idempotent per episode_id) curl -s https://hypermove.duckdns.org/api/mcp -H 'authorization: Bearer ' -d '{ "jsonrpc":"2.0","id":1,"method":"tools/call", "params":{"name":"submit_episode_log","arguments":{ "agent_id":"robot-42", "episodes":[{"episode_id":"ep-1","agent_id":"robot-42","timestamp":"2026-08-01T10:00:00Z", "steps":[{"action":"grip","result":"timeout"}],"outcome":"failure"}] }}}' # 2 — run the pipeline (preprocess -> cluster -> extract -> consolidate -> prune), # bounded by budget_usd — never spends more than this per call, independent of the # gateway's own free-tier metering. curl -s https://hypermove.duckdns.org/api/mcp -H 'authorization: Bearer ' -d '{ "jsonrpc":"2.0","id":2,"method":"tools/call", "params":{"name":"start_dream","arguments":{ "agent_id":"robot-42","config":{"budget_usd":0.05,"preset":"balanced"} }}}' # 3 — ask what it learned, any time later curl -s https://hypermove.duckdns.org/api/mcp -H 'authorization: Bearer ' -d '{ "jsonrpc":"2.0","id":3,"method":"tools/call", "params":{"name":"query_dream","arguments":{"agent_id":"robot-42","query":"gripper timeout"}}}' ``` `config` must be nested exactly as shown — `{agent_id, config: {budget_usd, preset}}`, not flattened. `preset` is one of `frugal | balanced | thorough`; `outcome` in an episode is one of `success | failure | timeout` (no `partial` — map ambiguous outcomes to the closest of the three). `get_dream_stats` reports the same cost/token figures the gateway's own per-call audit ledger (`mcp_calls.tokens_used` / `cost_usd`, added 2026-08-01) records for that `start_dream` call — the two are guaranteed to agree, since they're written from the same run. Resources and prompts compose on top of the tools above (`FEATURE_MCP_RESOURCES`): `hypermove:///agents/{agent_id}/dream/{summary,rules,errors,stats}` and the `dream/summarize_today`, `dream/suggest_policy_updates`, `dream/compare_before_after` prompt templates. ## Agent-skills install & run locally — MCP is optional HyperMove agent-skills are **self-contained**: 1. Fetch a skill's SKILL.md from `GET /api/skills/?format=md` (or the `skills.install` tool above). 2. Save it into your host's skills directory. 3. It autoloads and runs **in your own workspace by following its procedure — no MCP connection required**. The gateway above is only for the *external-protocol* layer: connect it when a skill needs live cross-chain data (`data.call`) or a payment (`payments.settle`). Browse the catalog at `GET /api/skills`. ## 1 — Connect your wallet (required by default) `/api/mcp` requires a key — there is no anonymous free tier. **[hypermove.duckdns.org/mcp-connect](/mcp-connect)** is the fastest path: - Connects your wallet. - Has you sign one free message (no gas). - Issues a bearer token from that signature. Email-only sign-in via WorkOS is also available from the same page for users without a wallet. No wallet and no browser at all? See [Get a key — no wallet needed](/docs/agent-auth) for a terminal-only flow. ```bash # Wallet flow happens in-browser at /mcp-connect. Scripted equivalent (WorkOS): open https://hypermove.duckdns.org/api/mcp/authorize # → WorkOS AuthKit → /api/mcp/callback → redirects to /mcp-connect?token=… # (send `Accept: application/json` to get { "token": "…" } back instead of the redirect) ``` Both `FEATURE_HYPERMOVE_MCP_GATEWAY_V1=true` and `FEATURE_MCP_AUTH_WORKOS=true` must be set — the master flag alone routes to the legacy 2-tool surface, which never checks auth. Local dev needs no WorkOS: set `HYPERMOVE_DEV_UNAUTHENTICATED=true` and call from `localhost`. ## 2 — Search (free tier: 5 / 24h) ```bash curl -s https://hypermove.duckdns.org/api/mcp \ -H 'authorization: Bearer ' \ -H 'content-type: application/json' \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call", "params":{"name":"search","arguments":{"query":"token balances base","limit":5}}}' ``` Every response follows the **envelope contract** — read payloads via `.data`: ```jsonc { "ok": true, "data": { "hits": [ /* … */ ], "total": 5, "nextSteps": "…" } } // on failure: { "ok": false, "error": { "service": "moralis", "kind": "soft-empty", "message": "…", "hint": "…" } } ``` `kind: "soft-empty"` means *the service returned nothing* — NOT an error. Never treat it as absence. ## 3 — Daily news + insight ```bash # search today's news -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"news.search","arguments":{"query":"restaking"}}}' # AI insight for one project -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"codemode.news.insight","arguments":{"project":"x402"}}}' ``` ## 4 — Choose a network, then pay Discover options, then select chain + rail + asset via headers: ```bash # what can I pay on? -d '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"codemode.payments.networks","arguments":{}}}' # after the free tier, the gateway returns JSON-RPC error -32402 with an x-payment-required # challenge listing chains + assets + amounts. Select and pay: curl -s https://hypermove.duckdns.org/api/mcp \ -H 'authorization: Bearer ' \ -H 'x-payment-chain: xrpl-mainnet' \ -H 'x-payment-rail: x402' \ -H 'x-payment-asset: RLUSD' \ -H 'x-payment: ' \ -d '{"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"name":"search","arguments":{"query":"nft"}}}' ``` One settlement opens a **session bundling 100 queries** at that tier — per-query gas stays viable. ## Rollback runbook (under 60s) 1. Set `FEATURE_HYPERMOVE_MCP_GATEWAY_V1=false` (or flip any single sub-flag) in the host env. 2. Redeploy / restart. `/api/mcp` immediately returns to the legacy 2-tool surface. 3. No data is dropped — flags never touch tables or sessions. Sub-flags for partial rollback: `FEATURE_MCP_AUTH_WORKOS`, `FEATURE_MCP_RATE_LIMIT`, `FEATURE_MCP_PAYWALL`, `FEATURE_MCP_DATA_ADAPTERS_V1`, `FEATURE_MCP_VECTOR_SEARCH`, `FEATURE_MCP_NEWS_V1`, `FEATURE_MCP_AGENTIC_V1`, `FEATURE_HYPERMOVE_TOOLS`, `FEATURE_MCP_BUILDER_BRIEF`, `FEATURE_MCP_XRPL_V3`, `FEATURE_MCP_FLARE_V1`, `FEATURE_MCP_CONFIDENTIAL_V1`, `FEATURE_MCP_INSTRUCT_V1`, `FEATURE_MCP_TOKEN_PROFILE_V1`, `FEATURE_MCP_DREAM_CYCLE`, `FEATURE_MCP_RESOURCES`, `FEATURE_MCP_GUARDIANS`. ## Health & spec (public, no auth) ```bash curl https://hypermove.duckdns.org/.well-known/webmcp.json # manifest: tools, endpoints, auth mode curl https://hypermove.duckdns.org/api/mcp/health # { ok, gateway_enabled, tools[], commit, deployed_at } curl https://hypermove.duckdns.org/api/mcp/spec # OpenAPI-3.1-style super spec ``` `/api/mcp/health`'s `commit` / `deployed_at` fields let you confirm which build is actually live before trusting any "should be fixed now" claim — check it first. --- # Dream Cycle > **Your agent forgets everything between sessions. Dream Cycle fixes that.** > Log what happened during the day (`submit_episode_log`), trigger a consolidation pass > (`start_dream`), and the next session reads back small, durable lessons > (`query_dream`) instead of re-learning the same mistake. Zero setup — it's on by > default on the same `https://hypermove.duckdns.org/api/mcp` endpoint you already use. ## Why this exists Every MCP session an agent runs starts from zero. If it discovers "the gripper needs a 200ms cooldown before retry" today, that lesson is gone tomorrow — unless you paste the whole transcript back into context, which is slow and expensive at scale. Dream Cycle is an offline consolidation pass, modeled on how research like ["sleep-time compute"](https://arxiv.org/abs/2504.13171) and offline memory-consolidation work: cheap, rule-based passes do most of the work; a small LLM call only touches *compressed summaries*, never raw logs. The output is a handful of short, confidence-scored memories your agent can pull in a single call — cents per day, not dollars. ## The 30-second mental model ``` during the day: submit_episode_log(agent_id, episodes) → cheap, no LLM call end of day: start_dream(agent_id, {budget_usd: 0.10}) → runs the whole pipeline next session: query_dream(agent_id, "gripper timeout") → "retry after 200ms cooldown" ``` That's the whole surface. Everything else (resources, prompts, presets, stats) is optional sugar on top of those three calls. ## Semantic-preservation canary Set `FEATURE_MCP_DREAM_SEMANTIC_PRESERVATION=true` to enable the quality gate. It preserves observations, errors, and tags in clustering/extraction, rejects generic memories with no meaningful source overlap, and adds semantic/truncation counters to `get_dream_stats`. It is off by default during canary rollout. `steps[].result` is accepted as a one-release alias for `observation_summary` and is reported in `normalized_fields`. For an affected completed run, call `preview_dream_repair` first. It proposes generic memory IDs without changing data. `apply_dream_repair` requires those exact IDs and `confirm: true`; it quarantines them and replays only the retained source run. ## For humans — what you get and what it costs - **No new infra.** Same endpoint, same auth, same bearer token. Dream Cycle just adds 5 tools to what your agent already sees when it calls `tools/list`: `submit_episode_log`, `start_dream`, `get_dream_config`, `query_dream`, `get_dream_stats`. Also 4 resources and 3 prompts — see below. - **All 5 tools are free.** They never hit the paywall or the 5-free-queries/24h limit. Spend is capped by your own `budget_usd` per cycle (default $0.10), not by HyperMove's tiers. - **The one metered piece — extraction's LLM call — settles in RLUSD on XRPL, via T54.** When the extraction step is priced, the 402 challenge names an amount in RLUSD; you sign a presigned XRPL `Payment` yourself (no API key, no custodial wallet) and it settles through [T54's XRPL x402 Facilitator](https://xrpl-x402.t54.ai) in 3-5 seconds for sub-cent fees. Full mechanics, real verified testnet transactions, and a runnable demo: see the [README's T54 + XRPL section](https://github.com/phamdat721101/hypermove-app#t54--xrpl--the-settlement-rail-behind-every-rlusd-priced-tool-call) and [`docs/posts/dream-cycle-rlusd-t54-xrpl-agent-payments.md`](https://github.com/phamdat721101/hypermove-app/blob/main/docs/posts/dream-cycle-rlusd-t54-xrpl-agent-payments.md). - **Nothing changes if you never call `start_dream`.** Logging with `submit_episode_log` costs nothing and does nothing until you trigger a cycle — no background jobs, no surprise charges. - **Your data stays yours.** Memories are scoped per `agent_id`, bound to whichever session first used that ID — a different account can never read or write into it. ## For agents — the fastest path to using this 1. Connect to `https://hypermove.duckdns.org/api/mcp` the same way you already do (see [MCP Gateway](/docs/mcp-gateway) if you haven't yet — bearer token from [/mcp-connect](/mcp-connect) or the [no-wallet flow](/docs/agent-auth)). 2. Call `tools/list` — if Dream Cycle is enabled (default: yes) you'll see the 5 tools below. 3. Log episodes as you go. Trigger a cycle whenever you want. Query before you plan. No separate signup, no separate API key, no SDK to install — it's 3 JSON-RPC calls against a tool surface you already discover automatically. ## Pick your agent_id once, then it's yours The **first** call to `submit_episode_log` or `start_dream` for a new `agent_id` claims it for your session. After that, only your session can write to it — pick a stable, unique string (e.g. your robot's serial number, your bot's slug) and reuse it every day. ## 1 — Log what happened ```bash curl -s https://hypermove.duckdns.org/api/mcp \ -H 'authorization: Bearer ' \ -H 'content-type: application/json' \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{ "name":"submit_episode_log", "arguments":{ "agent_id":"robot-42", "episodes":[{ "episode_id":"run-2026-07-26-001", "agent_id":"robot-42", "timestamp":"2026-07-26T09:00:00Z", "task_type":"pick_and_place", "outcome":"failure", "steps":[ {"action":"grip"}, {"action":"retry"}, {"action":"grip_again","error":"gripper timeout"} ], "tags":["pick_and_place","gripper"] }] } }}' ``` Returns `{ "ingested_count": 1, "rejected": [] }`. Call this as many times a day as you want — resubmitting the same `episode_id` is a safe no-op, never a duplicate. No LLM call happens here; this step is free and near-instant. `outcome` accepts exactly three values: `success`, `failure`, or `timeout` — there is no `"partial"` state. For a task that partly succeeded, pick whichever of the three best matches the primary goal (usually `success` if the main objective was met despite a caveat). This is also declared as an `enum` on the tool's `inputSchema`, so MCP clients that render tool schemas surface the valid values without a round-trip. ## 2 — Trigger a Dream Cycle ```bash curl -s https://hypermove.duckdns.org/api/mcp \ -H 'authorization: Bearer ' \ -H 'content-type: application/json' \ -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{ "name":"start_dream", "arguments":{"agent_id":"robot-42","config":{"budget_usd":0.10,"preset":"balanced"}} }}' ``` Returns `{ "run_id":"…", "status":"started" }` and, once the pipeline finishes inside that same call, the run reaches `completed` or `partial` (if the budget ran out — still useful, never wasted). Presets: `frugal` (cheapest, fewer clusters), `balanced` (default), `thorough` (most coverage, higher cost). Call this once a day, or whenever you have a batch of new episodes worth consolidating — there's no scheduler, you decide when. ## 3 — Query before you plan ```bash curl -s https://hypermove.duckdns.org/api/mcp \ -H 'authorization: Bearer ' \ -H 'content-type: application/json' \ -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{ "name":"query_dream", "arguments":{"agent_id":"robot-42","query":"gripper timeout","top_k":5,"min_confidence":0.5} }}' ``` Returns memories sorted by relevance: ```jsonc { "memories": [ { "memory_id":"…", "type":"error_pattern", "content":"gripper timeout after retry", "confidence":0.9, "importance":0.8 } ] } ``` Read this **before** your agent starts planning a task — it's the whole point. ## Skip the query — read memories as MCP resources instead If your MCP client supports resources, you can pull the same data with no arguments to fill in — just the right URI for your `agent_id`: | Resource | Contents | |---|---| | `hypermove:///agents/{agent_id}/dream/summary` | Last run's status + how many memories exist | | `hypermove:///agents/{agent_id}/dream/rules` | High-confidence rules | | `hypermove:///agents/{agent_id}/dream/errors` | Known error patterns | | `hypermove:///agents/{agent_id}/dream/stats` | Budget spent, stages completed, memory count | ## Skip the prompt engineering — use the built-in prompts | Prompt | What it does | |---|---| | `dream/summarize_today(agent_id)` | Plain-language summary of the last cycle | | `dream/suggest_policy_updates(agent_id, task_type)` | Concrete policy changes for one task type | | `dream/compare_before_after(eval_scores_json)` | Compares your own before/after eval numbers | These are templates, not tools — an MCP client that supports `prompts/get` renders them pre-filled; there's nothing extra to call. ## Check in on a cycle ```bash -d '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"get_dream_stats","arguments":{"agent_id":"robot-42"}}}' -d '{"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"name":"get_dream_config","arguments":{"agent_id":"robot-42"}}}' ``` `get_dream_stats` → `last_run_at`, `status`, `budget_used_usd`, `stages_completed`, `memories_count`, and (additive) `stage_summaries` — a coarse, non-content-leaking breakdown of what each stage did: - How many episodes preprocessing discarded, and why. - How many clusters extraction attempted, skipped, or failed. - How many of extraction's candidate insights pruning actually promoted vs. discarded. If `memories_count` stays `0` after a run with real episode data, check `stage_summaries.pruning_summary` first — a nonzero `candidates_extracted` with `candidates_promoted: 0` means extraction genuinely found something that didn't survive pruning (not a silent failure to process your data). `get_dream_config` → whatever `budget_usd`/`preset` you last set. Before filing a "this looks broken" report, check two health endpoints — both return a `commit` field (added 2026-07-27) so you can confirm the fix you're expecting is actually deployed, rather than guessing from a maintainer's say-so: - `GET /api/mcp/health` — the gateway process. - `GET https://hypermove.duckdns.org/llm/health` — the extraction service. ## What a fresh agent needs for its first promoted memory **One episode with at least one non-empty `steps` entry is enough.** There is no meaningful confidence/importance threshold standing between a fresh agent and its first promoted memory: - Pruning's defaults (`min_confidence: 0`, `min_importance: 0`) accept anything. - Every new memory is inserted at `confidence: 0.5, importance: 0.5` — already well above that floor. - A cluster of size 1 (a single unmatched episode) is a valid cluster; there's no minimum cluster size either. What actually determines whether you get a memory: - **`steps: []` (zero steps) is discarded before extraction ever sees it** — this is the one real filter, and it shows up in `stage_summaries.preprocessing.discard_reasons` as `empty_steps`. Give every episode at least one `steps` entry with a real `action`. - **Extraction has to find something "rule/preference/error_pattern/fact"-shaped.** A single bland episode (e.g. `{"action": "did the thing"}` with no error, no context) may legitimately produce zero insights for its cluster — that's a correct outcome for low-signal input, not a bug. `stage_summaries.extraction.candidates_extracted` tells you whether this happened; `clusters_failed`/`clusters_skipped` tell you whether it was a transient extraction failure or a budget cutoff instead. - **`stage_summaries` is the tool for "why didn't anything promote," not guesswork.** Read `pruning_summary.candidates_extracted` vs. `candidates_promoted` first, every time, before assuming something is broken. If a query on a fresh agent still returns nothing after a run with genuinely descriptive episode content (real `action`s, real `error`s on failures), check `stage_summaries` before filing a report — it will show you exactly which stage the signal was lost at. ## Confidential extraction on Flare FCC (opt-in, real Coston2 deployment) By default, Dream Cycle's extraction step calls `llm-service` directly over plain HTTP. If you want that dispatch attested through HyperMove's own Flare Compute Extension (FCE) — a real, deployed TEE-proxy/extension pair on Coston2, not a mock — opt in per-run: ```bash curl -s https://hypermove.duckdns.org/api/mcp \ -H 'authorization: Bearer ' \ -H 'content-type: application/json' \ -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{ "name":"start_dream", "arguments":{"agent_id":"robot-42","config":{"budget_usd":0.10,"confidential":true}} }}' ``` Gated by `FEATURE_MCP_DREAM_CONFIDENTIAL=true` (default OFF). Under the hood this routes extraction through the `flare.instruct.dispatch` tool (`GENERIC_AGENT_TASK` opType) instead of calling `llm-service` directly — see [`flare.instruct.dispatch`](#flareinstructdispatch-standalone-tool) below for the full mechanics and what's currently real vs. still a hard boundary. ### What "confidential" honestly means here — read this before assuming more **This ships "TEE-attested dispatch," not "the LLM call itself runs inside a TEE."** The actual token generation still happens in the same non-TEE `llm-service` process the plain (non-confidential) path calls — the extension's Go handler reaches out to it over the network exactly like any other external HTTP call. If you need the LLM call itself to be confidential, that's explicitly out of scope for what's shipped; nothing here claims otherwise. **Real, independently verifiable, live on Coston2 (as of 2026-08-08):** - `HyperMoveInstructionSender` deployed at [`0xB4864BB622F3020a5d424ff2CC20738b3327f7E2`](https://coston2-explorer.flare.network/address/0xB4864BB622F3020a5d424ff2CC20738b3327f7E2) — check its bytecode with any RPC client (`eth_getCode`), it's real. - HyperMove's own `tee-proxy` publicly answers at `https://hypermove.duckdns.org/tee-proxy/info` — a real, signed `TeeInfoResponse` from the registered extension, not canned data. - `flare.instruct.dispatch` genuinely reaches the deployed contract and gets real on-chain responses (including real revert reasons while the deployment was mid-setup — nothing was ever silently faked). **The current, honest limit:** completing on-chain TEE-machine registration requires a real Google Confidential Space attestation JWT. This deployment runs under `SIMULATED_TEE=true` (no GCP Confidential VM hardware requested) — its attestation value is the plain string `magic_pass`, a real, documented "testing outside of the google cloud" sentinel, never a fabricated-but-plausible fake quote. Until real hardware (or a documented simulated-registration path from Flare) exists, `start_dream({confidential: true})` will report the honest `fcc_dispatch_failed`/non-genuine outcome for every cluster — **zero cost is ever charged for a non-genuine confidential attempt**, matching the same discipline the plain extraction path already uses for a failed/unreachable `llm-service` call. Check `stage_summaries` (see "Check in on a cycle" above) to see this distinction directly rather than guessing from silence. ### Two different things are both called "confidential" — Coston2 vs. Songbird Everything above describes **HyperMove's own dev-only extension on Coston2** — the code path this deployment actually exercises today. That is deliberately a different system from **real Flare Confidential Compute (FCC) on Songbird**, and the codebase keeps the two separate on purpose (`src/lib/mcp/providers/flare.ts`): - **`isHyperMoveTeeExtensionLive(network)`** — `true` only for `network === 'coston2'`, and only after a real `fetch('/health')` against HyperMove's own `tee-proxy` succeeds. This is what everything above (`HyperMoveInstructionSender`, `tee-proxy/info`, `SIMULATED_TEE=true`, `magic_pass`) is checking. It confirms HyperMove's own extension is configured and reachable — nothing more. - **`isFccLiveOnNetwork(network, client)`** — `true` only for `network === 'songbird'`, and only after a live on-chain query against Flare's own `FlareContractRegistry` finds a registered `FlareConfidentialCompute` entry. **As of this writing, this returns `false`** — Flare has not deployed the FCC contract to Songbird yet. This is Flare's own infrastructure timeline, not something this codebase can fix or work around. Which one a given `start_dream({confidential:true})` call actually checks is controlled by `DREAM_CONFIDENTIAL_NETWORK` (default `coston2`, in `dream/extract.ts`). **Never conflate a passing Coston2 liveness check with "real Flare FCC is live"** — they are different claims about different infrastructure, and the code's own doc comments are emphatic about this distinction for exactly this reason. Either way, `confidential: true` never silently fails: it always either produces a genuinely attested result, or returns an explicit reason it couldn't (see the fallback-reason table below). ### If you request `confidential:true` and the gate isn't satisfied, you're told — not silently downgraded `FEATURE_MCP_DREAM_CONFIDENTIAL` off, or on but with no settled `confidential`-tier payment, both mean the run happens in plaintext instead of via Flare FCC — this was already true before 2026-08-10. What changed: `start_dream`'s own response now says so, instead of requiring a separate `get_dream_config` call to discover it after the fact. These 3 fields appear **only** when your request actually touched `confidential` (an explicit `true`, or an inherited `confidential_default` of `true`) — a plain non-confidential call's response is unaffected, byte-identical to before this fix: ```json { "run_id": "...", "status": "started", "confidential_requested": true, "confidential_actual": false, "confidential_fallback_reason": "feature_disabled" } ``` `confidential_fallback_reason` is one of: - `"feature_disabled"` — `FEATURE_MCP_DREAM_CONFIDENTIAL` is off. - `"no_settled_payment"` — the flag is on, but no active/consumable `confidential`-tier paid session exists (this case already returned `status: "error"` with a `payment_challenge` before this fix — the 3 fields above are now included on that existing error response too, for a consistent signal either way). A successful confidential run (flag on + settled payment) reports `confidential_actual: true` with no `confidential_fallback_reason` field at all. ## `flare.instruct.dispatch` (standalone tool) Beyond Dream Cycle, `flare.instruct.dispatch` is callable on its own — submit either a `FINANCIAL_ACTION` (`SWAP`/`SETTLE`, still an honest not-yet-implemented stub pending Flare's Protocol Managed Wallets interface) or `GENERIC_AGENT_TASK` (`COMPUTE`) instruction to HyperMove's Coston2 extension and poll for the result: ```bash curl -s https://hypermove.duckdns.org/api/mcp \ -H 'authorization: Bearer ' \ -H 'content-type: application/json' \ -d '{"jsonrpc":"2.0","id":6,"method":"tools/call","params":{ "name":"flare.instruct.dispatch", "arguments":{"opType":"GENERIC_AGENT_TASK","message":{"taskType":"dream.extract","payload":"agent retried gripper pick after timeout"}} }}' ``` Gated by `FEATURE_MCP_INSTRUCT_V1` (opt-in). Honest by construction at every stage: | Stage | Honest outcome if not ready | |---|---| | Feature flag off | `feature_disabled` | | Extension not deployed/configured | `not_configured`, names the exact env vars to set | | On-chain dispatch itself fails (e.g. extension ID not yet set, no TEE machine registered) | `dispatch_failed`, carries the real on-chain revert reason verbatim | | Dispatch succeeds, `taskType` isn't `dream.extract` | The extension's own honest not-yet-implemented refusal (status 0), never a fabricated success | Full architecture, the exact dependency chain between the indexer/proxy/extension, and every real bug found and fixed while deploying this live: see [`services/tee-extension/README.md`](https://github.com/phamdat721101/hypermove-app/blob/main/services/tee-extension/README.md) in the repo — it documents the complete Coston2 deployment (contract address, real transaction hashes, the exact hard boundary at TEE-machine registration) in detail. ## What's on by default, and how to turn it off Dream Cycle ships **on**, same as the rest of the MCP Gateway's v3.0+ tools — no flag to flip to start using it. If you need to disable it (e.g. to roll back a bad deploy): ```bash FEATURE_MCP_DREAM_CYCLE=false ``` One env var removes all 5 tools, all 4 resources, and all 3 prompts in one flip — nothing else on the gateway changes. ## Known limits (Phase 1 — honest, not hidden) - **`start_dream` still always runs immediately when called** — the manual path is unchanged and always available, on-demand, regardless of the scheduler below. - **Server-side `trigger_criteria` enforcement is opt-in, not default (2026-07-27).** By default, nothing runs your cycles for you: - Set `trigger_criteria` in `config` and it's saved either way. - It's only *enforced* automatically if the operator has enabled `FEATURE_MCP_DREAM_SCHEDULER=true` (off by default — see "Server-side scheduling" below for why). - Without it, exactly as before: you decide when to call `start_dream`. - **No quality benchmark is published yet.** The pipeline is fully functional and budget-safe; the "how much better did my agent get" number isn't measured in this release. - **Best for motion/episode-style agents.** Dream Cycle assumes step-by-step episode logs with an outcome (success/failure/timeout) — it's not a general-purpose memory store for arbitrary unstructured text. ## Server-side scheduling (opt-in, added 2026-07-27) If you set `trigger_criteria` in `start_dream`'s `config` (`time_window_utc`, `min_episodes`, `min_raw_tokens`), it's always persisted — but by default nothing reads it back automatically. An operator running this MCP gateway can opt into server-side enforcement: ```bash FEATURE_MCP_DREAM_SCHEDULER=true ``` Once enabled, an in-process hourly tick checks every agent's `trigger_criteria` and fires `start_dream` on your behalf when your conditions are met — no external cron, no script you have to remember to run. This is deliberately **opt-in, not the default** (unlike every other Dream Cycle flag) because it's the first feature in this gateway that autonomously spends budget across every registered agent with no per-call human trigger. Two independent ceilings bound worst-case cost per tick regardless of how many agents are configured: - `DREAM_SCHEDULER_MAX_BUDGET_USD_PER_TICK` — default $1.00 total across all agents per tick. - `DREAM_SCHEDULER_MAX_AGENTS_PER_TICK` — default 20. An agent beyond either ceiling is deferred to the next tick, not silently dropped. `get_dream_stats`'s `triggered_by` field (`'manual'` or `'scheduler'`) tells you which path produced the last run. If you were already running your own external scheduler (e.g. a cron job calling `start_dream` directly), nothing about that changes: - The two paths are independent and can coexist. - Enabling the server-side scheduler on top of an existing external one will just mean both fire (consider disabling one if you do). Full technical detail, data model, and pipeline internals: [`docs/prd/dream-cycle-v1.md`](https://github.com/phamdat721101/hypermove-app/blob/main/docs/prd/dream-cycle-v1.md) in the repo. --- # LLM Service > **A separate, standalone process (`services/llm/server.ts`) that keeps model > API keys off the main app entirely.** It powers two things: turning a URL > into an agent-callable MCP server (`POST /scan`, used by [/tools/generate](/tools/generate)) > and Dream Cycle's memory extraction (`POST /dream/extract`, called automatically > by `start_dream` — you never call this route yourself). Most people reading this > page will never need to run their own copy of it. ## Live endpoint (agents: start here) HyperMove's own deployment of this service is already running, reachable over HTTPS (Caddy-fronted, Let's Encrypt cert) at: ``` https://hypermove.duckdns.org/llm ``` No setup, no key, no signup — every example below works against this address right now. Confirm it's up before anything else: ```bash curl https://hypermove.duckdns.org/llm/health # { "ok": true, "provider": "bedrock", "commit": "f1202e41...", "deployed_at": "2026-07-27T09:02:00Z" } ``` `commit`/`deployed_at` (added 2026-07-27) tell you which build is actually running: - It's a build-time constant injected by `scripts/deploy-vps.sh`, not a runtime `git` lookup. - Check this before filing "is X actually fixed yet" — compare `commit` against the commit SHA you expect to be live rather than trusting a maintainer's unverifiable "should be deployed now." The service itself still listens on plain HTTP internally (`localhost:3001` on the host): - Caddy terminates TLS and reverse-proxies `/llm/*` → `:3001` (stripping the `/llm` prefix). - Every route documented below is reachable as `https://hypermove.duckdns.org/llm/`. - The bare `http://:3001` address is no longer the documented public entry point — prefer the HTTPS domain above for anything crossing the public internet. If you're building an agent that uses **Dream Cycle** (`submit_episode_log` / `start_dream` / `query_dream` over MCP), you don't need this address at all — `start_dream` already calls this service internally, server-side. This address only matters if you're calling `/scan` directly, or self-hosting your own copy — see [Dream Cycle](/docs/dream-cycle) if that's not you. ## Do I need this page? Almost certainly not as a Dream Cycle or MCP Gateway **user** — extraction is already hosted and configured for you (see [Dream Cycle](/docs/dream-cycle)). This page is for: - **Agents/integrators** calling `POST /scan` directly to turn a URL into an MCP server (the endpoint above is all you need). - **Operators** deploying HyperMove's own infrastructure who need to configure or redeploy this service. - **Self-hosters** who want to point Dream Cycle's extraction stage at their own model, provider, or key instead of HyperMove's default. - **Anyone curious** what's actually running behind `/tools/generate` and Dream Cycle's `start_dream`. ## What it is A plain Node HTTP server (no framework), run with `tsx`, deployed as its own process independent of the main Next.js app. One config surface (`LLM_PROVIDER` + a matching API key) serves every route below — there's no per-route credential duplication. ```bash cd services/llm npm install PORT=3001 BEDROCK_API_KEY=... npx tsx server.ts # or: npm start (reads services/llm/.env.local automatically) ``` ## Configuration — one provider, one key ```bash LLM_PROVIDER=bedrock # bedrock (default) | anthropic | openai # bedrock — uses the Converse API (uniform request/response shape across # every Bedrock model, so swapping BEDROCK_MODEL never needs a code change): BEDROCK_API_KEY=... BEDROCK_REGION=us-east-1 # optional, this is the default BEDROCK_MODEL=deepseek.v3.2 # optional, this is the default — the # cheapest DeepSeek variant Bedrock hosts # ($0.62/$1.85 per 1M input/output tokens, # vs DeepSeek-R1's $1.35/$5.40) # anthropic: ANTHROPIC_API_KEY=... ANTHROPIC_MODEL=claude-sonnet-4-20250514 # optional # openai: OPENAI_API_KEY=... OPENAI_MODEL=gpt-4o # optional # Optional — quota/payment tracking (Supabase Postgres). Omitted → every # quota check no-ops permissively (unlimited, dev-friendly default). DATABASE_URL=postgres://... ``` Switching provider — or switching model within Bedrock — is one env var; every route (`/scan`, `/dream/extract`) picks it up automatically, no code change. **Dream Cycle users never need any of the above.** This key lives entirely on this service; the 5 Dream Cycle MCP tools (`submit_episode_log`, `start_dream`, `get_dream_config`, `query_dream`, `get_dream_stats`) never accept or require an API key parameter — see [Dream Cycle](/docs/dream-cycle). ## Routes | Route | Purpose | |---|---| | `GET /health` | `{ ok: true, provider: "bedrock" }` — confirms the process is up and which provider it's configured for. | | `POST /scan` | Crawl a URL, ask the model to synthesize an MCP manifest (tools + schemas) from the page, return it plus a ready-to-paste `mcpConfig`. Powers [/tools/generate](/tools/generate). | | `POST /dream/extract` | Extract `{rules, preferences, error_patterns, facts}` from a short episode-cluster summary. Called automatically by Dream Cycle's `start_dream` — see [Dream Cycle](/docs/dream-cycle). Not meant to be called directly by end users. | | `GET /quota?wallet=0x…` | Read a wallet's free-scan quota + tier. | | `POST /quota/consume` | Decrement one free scan for a wallet (`402` when exhausted). | | `POST /upgrade` | Verify an on-chain payment (native BTC or ERC-20) and upgrade a wallet to the pro tier for 30 days. | | `POST /register` | Persist a generated MCP manifest so it's servable later at `//`. | | `GET` / `POST //` | Serve a previously registered MCP manifest (GET) or handle JSON-RPC calls against its tools (POST) — the hosted-MCP surface `/scan` + `/register` produce. | ## 1 — Turn a URL into an MCP server ```bash curl -s -X POST https://hypermove.duckdns.org/llm/scan \ -H 'content-type: application/json' \ -d '{"url":"https://example.com","wallet":"0xYourWalletAddress"}' ``` Returns: ```jsonc { "manifest": { "name": "example-com-mcp", "tools": [ /* … */ ] }, "mcpConfig": { "mcpServers": { "example-com-mcp": { "url": "https://your-deploy/0x…/example-com-mcp", "transport": "http" } } }, "crawlData": { "url": "...", "title": "...", "toolCount": 2 } } ``` Paste `mcpConfig` straight into any MCP client's config file — the generated server is already registered (via `/register`, called internally) and servable at that URL. ## 2 — Dream Cycle extraction (you don't call this directly) ```bash curl -s -X POST https://hypermove.duckdns.org/llm/dream/extract \ -H 'content-type: application/json' \ -d '{"summary":"agent failed: gripper timeout during pick_and_place, retried without cooldown","max_output_tokens":150}' ``` Returns: ```jsonc { "rules": ["Add cooldown period after gripper timeout before retrying pick_and_place"], "preferences": [], "error_patterns": ["Gripper times out during pick_and_place when retried immediately without cooldown"], "facts": [] } ``` This exists so `src/lib/mcp/dream/extract.ts` has a real model to call — `start_dream` invokes it once per cluster automatically. On any error or malformed model output it degrades to `{rules:[],preferences:[],error_patterns:[],facts:[]}` rather than crashing the pipeline, so a Dream Cycle run always reaches a terminal status even if this service is briefly unreachable. ## Point Dream Cycle at your own instance (advanced, optional) By default, the main app's `DREAM_EXTRACT_URL` points at HyperMove's own deployed instance — nothing to configure: - It falls back to `LLM_SERVICE_URL`, then `http://localhost:3001/dream/extract`. - The connection is over the internal loopback (same host, server-to-server — no public network hop, so plain HTTP is correct there). If you're self-hosting and want a different model or provider for extraction specifically: ```bash # In the main app's env (not this service's): DREAM_EXTRACT_URL=https://your-llm-service.example.com/dream/extract ``` Your instance just needs to implement the same two-field-in, four-array-out contract shown in step 2 above. ## Deploy This service is deployed independently of the main app (its own process, its own restart lifecycle) — typically via `pm2`: ```bash cd services/llm npm install pm2 start "npx tsx server.ts" --name llm-service --cwd $(pwd) pm2 save ``` Health-check after any redeploy: ```bash curl http://localhost:3001/health # { "ok": true, "provider": "bedrock" } ``` Front it with a reverse proxy for public HTTPS access (HyperMove's own deployment uses Caddy — see the live endpoint at the top of this page): ``` hypermove.duckdns.org { handle_path /llm/* { reverse_proxy localhost:3001 } reverse_proxy localhost:3003 # the main Next.js app } ``` `caddy reload --config --adapter caddyfile` applies changes with zero downtime (no restart needed) once Caddy is already running against that file. ## A routing gotcha if you add a new route here `server.ts` uses a hand-rolled router (plain `if` chains on `req.method` + `url`, no framework) with one greedy catch-all near the bottom: any **exactly-two-segment** path (`//`) is claimed by the hosted-MCP handler before anything defined after it in the file gets a chance to run. If you add a new route whose path also happens to have exactly two segments (like `/dream/extract` did): 1. Place it **above** that catch-all in the file — same as `/quota/consume` and `/dream/extract` are today. 2. Otherwise it will silently return `204` for every request instead of running your handler. --- # n-payment > **n-payment@0.29.1** on npm — collapses x402 + ERC-8004 + BTC lending + OWS signing into one call. > Single peer dependency: `viem`. Dual CJS/ESM output. MIT-licensed. ## Three principles 1. **Agents never touch a private key.** OWS vault holds keys and enforces per-tx policy. 2. **BTC is the treasury; USDC is borrowed just-in-time.** Lock PegBTC → borrow → pay → repay → unlock. 3. **Five lines, not five hundred.** `fetchWithPayment()` unifies the lifecycle. ## Consumer — fetchWithPayment() ```ts // agent.ts import { createPaymentClient } from 'n-payment'; const client = createPaymentClient({ chains: ['goat-mainnet', 'base-mainnet'], ows: { wallet: 'my-agent' }, policy: { maxPerTransaction: 100_000n, // $0.10 cap per call maxPerDay: 10_000_000n, // $10.00 daily cap treasury: 'BTC', // PegBTC-collateralized rateLimit: { maxRequests: 100, windowMs: 60_000 }, }, }); const res = await client.fetchWithPayment('https://hypermove.duckdns.org/api/paid-endpoint'); console.log(await res.json()); // 200 OK, paid in ~1.2s ``` Under the hood: 1. GET the target URL → server returns HTTP 402 + WWW-Authenticate: x402-USDC. 2. Vault checks policy (spend cap, chain allowlist, token allowlist). 3. If treasury: 'BTC', the lending adapter locks PegBTC + borrows the exact USDC. 4. EIP-3009 authorize signature is produced inside the OWS vault. 5. The client retries with X-Payment header → server returns 200. ## Provider — createPaywall() ```ts // server.ts import { createPaywall } from 'n-payment/middleware'; import { Hono } from 'hono'; const app = new Hono(); app.use('*', createPaywall({ payTo: '0xYourAddress', chain: 'goat-mainnet', asset: 'USDC', routes: { '/api/paid-endpoint': { priceMicroUsdc: 10_000n }, // $0.01/call }, })); app.get('/api/paid-endpoint', (c) => c.json({ ok: true })); export default app; ``` One middleware call. Works with Express, Hono, Fastify, or raw fetch. ## Paid MCP Server ```ts // paid-mcp-server.ts import { createPaidMcpServer, paidTool } from 'n-payment/agent'; const server = createPaidMcpServer({ name: 'MyAgentService', payTo: '0xYourAddress', chain: 'goat-mainnet', tools: [ paidTool({ name: 'forecast', description: 'Get weather forecast', price: 10_000n, handler: async ({ city }) => ({ city, temp: 22 }), }), ], }); await server.listen(3000); ``` ## 14-protocol matrix | Protocol | Coverage | Chains | |---|---|---| | x402 | HTTP 402 handshake | GOAT, Base, Arb, Optimism | | EIP-3009 | Authorized USDC transfer | Base, Arb, Polygon | | MPP | Multi-Party split | GOAT, Base | | Stellar Channels | Sub-cent micropayments | Stellar | | Wormhole NTT | Native Token Transfers | Base, Solana, Sui | | Circle Gateway | USDC mint/burn | Base, Solana | | RLUSD | Ripple USD stablecoin | XRPL, Base | | XRPL x402 | XRPL-native MPT paywall | XRPL | | ERC-8004 | Agent identity + reputation | Base, Celo | | Aave V3 GHO | Idle USDC treasury yield | Base, Arb | | OWS Vault | Vault-bound signing | all 27 chains | | PegBTC Lending | JIT USDC from BTC | GOAT | | Flare FXRP | Bridged XRP gas + asset | Flare | | Initia VIP | Validator-incentive settle | Initia | ## Links - [npm · n-payment](https://www.npmjs.com/package/n-payment) - [GitHub](https://github.com/phamdat721101) - [Book a demo](https://calendly.com/phamdat721101/30min) ---