sera-mcp

mcp
Security Audit
Warn
Health Pass
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Community trust — 10 GitHub stars
Code Warn
  • process.env — Environment variable access in src/cli.ts
  • process.env — Environment variable access in src/index.ts
Permissions Pass
  • Permissions — No dangerous permissions requested

No AI report is available for this listing yet.

SUMMARY

Multi-currency settlement MCP for AI agents. 32 tools over Sera Protocol's stablecoin FX rails. Open source.

README.md

sera-mcp

The core MCP server for Sera Protocol. Turns any agent into a multi-currency agent by exposing Sera Protocol — stablecoin FX settlement — as one standard tool layer. 32 tools, 5 resources, 4 slash-prompt templates. Works with Claude Code, Claude Desktop, Cursor, OpenAI Agents SDK, OpenClaw, Hermes, NanoClaw, and any other MCP-compatible host.

Who this is for: agent builders and ops engineers who need their agent to discover currencies, quote, route, and execute stablecoin FX swaps through one standard tool interface.

Companion repo: Josh-sera/sera-agents — templates, examples, x402 services, and host integrations built on top of this MCP. Site: agents.sera.cx.

For deeper reading, see ARCHITECTURE.md, SECURITY-MODEL.md, and CHANGELOG.md.

This package also ships a sera CLI for cron jobs, CI scripts, and ops debugging — see CLI section below.

What you get

32 tools across 9 categories:

Category Tools
Discovery list_currencies, get_markets
Pricing & analytics get_fx_rate, compare_to_external_fx, multi_source_mid, spread_radar
Liquidity probing scan_markets, find_deals, probe_depth, round_trip_cost, infer_book
Quote & execute get_quote, prepare_swap, execute_swap, convert_and_send, quote_recipient_amount, find_cheapest_settlement_path, limit_watcher
Maker maker_quote_ladder
Treasury get_balances, treasury_value, exposure_report, rebalance_plan, pay_invoice
Settlement settlement_status
History fx_history, fx_volatility, corridor_pnl
Admin doctor

5 resources (sera://currencies, sera://markets, sera://config, sera://help/tools, sera://help/quickstart) — hosts can browse without burning tool-call budget.

4 slash-prompt templates for common workflows: sera.deal_scan, sera.treasury_brief, sera.invoice_optimizer, sera.fx_integrity_check.

Install

git clone <this-repo>
cd sera-mcp
npm install
npm run build

Requires Node 18.17+. Default install needs zero env vars — sensible defaults are baked in.

Wire it in

Claude Code (one line)

claude mcp add sera --scope user \
  --env SERA_NETWORK=mainnet \
  --env POLICY_PRESET=standard \
  -- node /absolute/path/to/sera-mcp/dist/index.js

Claude Desktop

~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "sera": {
      "command": "node",
      "args": ["/absolute/path/to/sera-mcp/dist/index.js"],
      "env": {
        "SERA_NETWORK": "mainnet",
        "POLICY_PRESET": "standard"
      }
    }
  }
}

Cursor

Settings → MCP → add a stdio server pointing at node /absolute/path/to/sera-mcp/dist/index.js with the same env.

Any MCP client over stdio

SERA_NETWORK=mainnet POLICY_PRESET=standard node dist/index.js

Speaks MCP over stdio. The server prints structured JSON status to stderr; stdout is reserved for the protocol.

Streamable HTTP (remote / web-served)

# Default: localhost only, DNS-rebinding protection auto-enabled, stateful sessions
node dist/index.js --transport http --port 3848

# Bind public with allowedHosts header validation
node dist/index.js --transport http --host 0.0.0.0 --port 3848 \
  --allowed-hosts mcp.mydomain.com,localhost

# Serverless / stateless mode
node dist/index.js --transport http --stateless

Endpoints:

  • POST /mcp — JSON-RPC requests
  • GET /mcp — SSE stream for notifications (stateful mode)
  • DELETE /mcp — session terminate
  • GET /health — liveness probe

⚠️ NO BUILT-IN AUTH ON STREAMABLE HTTP

Anyone who can reach the bound port can call every registered Sera tool. The transport ships with DNS-rebinding protection for localhost binds and a public-bind startup guard that refuses to start when binding to a non-loopback host without --allowed-hosts or an explicit SERA_HTTP_ALLOW_UNAUTHENTICATED_PUBLIC=true acknowledgment. Do not set the ack env in production.

Safe options:

  • Localhost (default): --host 127.0.0.1 — DNS rebinding protection auto-enabled.
  • Behind an auth-handling reverse proxy: --host 0.0.0.0 --allowed-hosts mcp.mydomain.com. The proxy is the trust boundary; it must handle auth (OAuth, JWT, mTLS, Cloudflare Access — your call).
  • Future: OAuth 2.1 + RFC 8707 Resource Indicators per MCP spec v2025-06-18. Tracked in roadmap.

See SECURITY-MODEL.md for the full deployment matrix.

Verify install

In a new agent session, ask:

Call sera.doctor()

Returns a one-shot self-check: API health, network sanity, signer mode, policy summary, persistence state. If everything is green you're wired correctly.

Configure

Most installs need nothing. Override via env:

Network

Variable Default Effect
SERA_NETWORK mainnet mainnethttps://api.sera.cx/api/v1. sepoliahttps://api-testnet.sera.cx/api/v1. URLs are hardcoded; you cannot redirect them via env.

Signer

Mode What happens
external (default) Server never signs. get_quote returns route_params; your wallet signs externally; execute_swap accepts the signature. Safe for distribution.
local Server holds SIGNER_PRIVATE_KEY and signs in-process. Enables convert_and_send. Only use on a trusted server with a wallet you've intentionally funded.
readonly All execution tools refuse. Discovery + analytics only.

Policy presets

Pre-baked bundles. Pick one with POLICY_PRESET=:

Preset Symbols Per-tx cap Daily cap Slippage
starter USDC, USDT $1,000 $5,000 25 bps
standard (recommended) USDC, USDT, XSGD, JPYC, MYRT, TGBP, EURC $5,000 $50,000 10 bps
sg-retail USDC, USDT, XSGD $2,000 $10,000 15 bps
open (none) (none) (none) 0

Override individual fields by setting the matching env (POLICY_MAX_NOTIONAL_USD, POLICY_DAILY_VOLUME_CAP_USD, POLICY_ALLOWED_SYMBOLS, etc.). Each override beats the preset.

Other

Variable Effect
POLICY_DRY_RUN=true All execute_swap calls refuse, regardless of signer mode. Paper-trading mode.
SERA_ENABLE_EXECUTION_TOOLS=false Hide the execution tool category (execute_swap, convert_and_send) from the MCP host entirely. Default true. Set false for public / multi-tenant deployments. Other tools (discovery, pricing, liquidity, quote planning, treasury, history) keep working.
SERA_HISTORY_DB=/path/to/file.db Enables fx_history, fx_volatility, corridor_pnl. SQLite log of every fx_rate + quote call this MCP serves.
LOG_LEVEL trace | debug | info (default) | warn | error. Structured JSON to stderr.
SERA_API_KEY + SERA_API_SECRET Required for get_balances, treasury_value, exposure_report, rebalance_plan, pay_invoice, settlement_status.

See .env.example for the full list with comments.

Security model

Built for distribution. Every layer assumes the install instructions might be hostile.

  • Hardcoded base URLs: SERA_BASE_URL is ignored by default. Overrides require a separately-named env (SERA_BASE_URL_ALLOW_CUSTOM=true) and emit a loud boot warning. A malicious install snippet can't redirect API traffic by setting one env var.
  • No redirects: undici maxRedirections: 0. Even a sera.cx subdomain can't 301 us elsewhere.
  • Quote registry: every get_quote registers {uuid → frozen route_params}. execute_swap refuses unknown uuids in local-signer mode (won't sign arbitrary intents) and refuses route_params mismatches in any mode.
  • Server-derived notional: daily volume cap is computed from route_params.maxInputAmount × token's USD value. Caller cannot lie about it.
  • Prompt arg sanitization: every prompt template arg is type-validated (address regex, fiat regex, numeric regex, symbol-list regex) before substitution into LLM context. Newline/SQL/instruction injections are rejected.
  • Policy gates: symbol whitelist, recipient whitelist, per-tx notional cap, rolling 24h volume cap, dry-run kill-switch.
  • Signer modes: server defaults to external and holds no key.
  • Caching: read-only endpoints have TTL caches with in-flight de-dupe. Quotes never cached.
  • Logging: structured JSON to stderr; never to stdout (which is reserved for MCP transport).

Run sera.doctor in any agent session for a live posture check.

Execution flow (external signer)

  1. Agent calls sera.get_quote with from, to, amount, owner_address (or simulate: true to probe with the burn address).
  2. MCP validates the request against policy and calls Sera POST /swap/quote.
  3. MCP returns uuid + route_params (the exact EIP-712 Intent struct) + caches the binding.
  4. Wallet signs route_params under the Sera EIP-712 domain:
    const domain = { name: 'Sera', version: '1', chainId, verifyingContract: seraAddress };
    const types = { Intent: [
      { name: 'taker', type: 'address' },
      { name: 'inputToken', type: 'address' },
      { name: 'outputToken', type: 'address' },
      { name: 'maxInputAmount', type: 'uint256' },
      { name: 'minOutputAmount', type: 'uint256' },
      { name: 'recipient', type: 'address' },
      { name: 'initialDepositAmount', type: 'uint256' },
      { name: 'uuid', type: 'uint256' },
      { name: 'deadline', type: 'uint48' },
    ]};
    const sig = await signer.signTypedData(domain, types, route_params);
    
  5. Agent calls sera.execute_swap with { uuid, signature }.

Quotes are single-use. On QUOTE_STALE / 410, re-quote — do not retry the same uuid.

Architecture

┌────────┐    sera.get_quote        ┌───────────────┐     POST /swap/quote     ┌──────┐
│ Agent  │ ───────────────────────▶ │  sera-mcp     │ ───────────────────────▶ │ Sera │
│        │                          │ (cache+policy │                          │  API │
│        │ ◀── route_params + uuid  │  +registry)   │ ◀──── uuid + route       │      │
└────────┘                          └───────────────┘                          └──────┘
     │  sign route_params (EIP-712)
     ▼
 wallet / external signer
     │  signature
     ▼
sera.execute_swap (uuid + sig) ──▶ sera-mcp ──▶ POST /swap ──▶ Sera ──▶ on-chain settlement
                                       │
                                       └─ enforces uuid binding, daily cap, dry-run

Source layout:

src/
├── index.ts                    MCP server entrypoint, tool/resource/prompt registration
├── config.ts                   env loading, hardcoded URL allowlist, AppContext
├── resources.ts                MCP resources (sera://...)
├── prompts.ts                  slash-prompt templates with arg sanitization
├── sera/
│   ├── client.ts               REST client + TTL cache wrapper
│   ├── tokens.ts               token resolver, decimals math
│   └── types.ts
├── signer/signer.ts            EIP-712 signer (external | local | readonly)
├── policy/policy.ts            whitelist, caps, presets, dry-run, daily volume gate
├── tools/                      32 tool handlers
└── util/
    ├── cache.ts                TTL cache + in-flight de-dupe
    ├── limit.ts                bounded-concurrency runner
    ├── external_fx.ts          Frankfurter / open.er-api / exchangerate.host clients
    ├── persistence.ts          optional SQLite log
    ├── logger.ts               structured stderr JSON
    ├── quote_registry.ts       uuid → route_params binding
    └── sanitize.ts             prompt arg validators

Status

Honest read of what's hardened vs what's still moving:

Surface Status Notes
stdio MCP transport Stable Used in production by Claude Code / Claude Desktop / Cursor / OpenAI Agents SDK
Read tools (discovery, pricing, liquidity, history, treasury reads) Stable Cached, rate-limit-tolerant, no side effects
Policy gates (whitelist, caps, dry-run, daily volume) Stable Server-derived notional; quote-registry binding
Quote tools (get_quote, prepare_swap, quote_recipient_amount) Stable EIP-712 Intent surface stable
External signer execution (execute_swap with caller signature) Stable Server holds no key
Local signer execution (execute_swap server-signs, convert_and_send) Operator-managed Requires SERA_SIGNER_MODE=local + intentionally funded wallet on a trusted host
API-key treasury tools (get_balances, treasury_value, pay_invoice, settlement_status) Operator-managed Require SERA_API_KEY / SERA_API_SECRET
Tool annotations (readOnly / destructive / idempotent / openWorldHint) Stable (v0.5.0) Every tool carries annotations the host runtime can use for confirmation UX.
Tool grouping + execution opt-in (SERA_ENABLE_EXECUTION_TOOLS) Stable (v0.5.0) Default true; set false to hide execute_swap + convert_and_send entirely.
convert_and_send only registered when SERA_SIGNER_MODE=local Stable (v0.5.0) Tool no longer surfaces when it can't work.
Streamable HTTP transport Stable (v0.8.0) Additive to stdio; --transport http opts in. Localhost-default with DNS-rebinding protection. No OAuth (bind to localhost or front with auth proxy).
Per-tool outputSchema + structuredContent Partial (v0.7.0) Live on doctor, list_currencies, get_fx_rate, market_health. Remaining tools incremental.
Read/exec endpoint split (/mcp/read, /mcp/exec) Planned When OAuth lands.
OAuth 2.1 + RFC 8707 Resource Indicators for remote HTTP Planned Required before any public/multi-tenant deployment.

Roadmap

  • Streamable HTTP transport — additive to stdio; for ChatGPT connectors and hosted/remote agents. SSE is not on the roadmap (deprecated upstream).
  • Tool grouping + SERA_ENABLE_EXECUTION_TOOLS flag — hides execution tools by default; opt-in for trusted hosts.
  • Subscriptions — push deal alerts instead of polling. MCP spec supports it; needs server-side subscriber state.
  • Multi-hop SOR explorer — for pairs with no direct corridor, plan via intermediate fiats.
  • Address risk screening — sanctions / OFAC hooks (needs an external provider).
  • Approval/allowance managersera.approval_status for ERC-20 approvals to the Sera vault.
  • Per-tool rate limits — defend against polling-loop DoS on the upstream quote engine.

CLI

This package ships a sera CLI alongside the MCP server. Same code, same Sera plumbing — just a different entry point for shell scripts and ops use.

# After build, either run directly:
node dist/cli.js doctor

# Or install globally for the `sera` command:
npm install -g .          # from this directory
# Or:
npm link                  # development convenience

sera doctor
sera fx USD SGD
sera quote USDC XSGD 100 --simulate
sera deals --min-bps 25 --json | jq
sera ladder USDT JPYC 30000
sera spread-radar USD,SGD,MYR,EUR,GBP,JPY

Run sera --help for the full command reference.

Built for:

  • Cron jobs / CI — automated FX dumps, daily deal summaries, alerting
  • Ops debugging — Sera engineering checking quote behavior without an agent
  • Power users — terminal-first people who don't want an LLM in the loop

The CLI uses the same handlers as the MCP server so anything an agent can do via sera.* tools, the CLI exposes as a command. See src/cli.ts.

Add --json to any command to get raw JSON for piping into jq / scripts.

License

MIT

Reviews (0)

No results found