Install
$ agentstack add mcp-sera-cx-sera-mcp ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
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](ARCHITECTURE.md), [SECURITY-MODEL.md](SECURITY-MODEL.md), and [CHANGELOG.md](CHANGELOG.md).
This package also ships a sera CLI for cron jobs, CI scripts, and ops debugging — see [CLI section](#cli) 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
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 requestsGET /mcp— SSE stream for notifications (stateful mode)DELETE /mcp— session terminateGET /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](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 | mainnet → https://api.sera.cx/api/v1. sepolia → https://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 | Don't ship this. |
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_URLis 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_quoteregisters{uuid → frozen route_params}.execute_swaprefuses 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
externaland 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)
- Agent calls
sera.get_quotewithfrom,to,amount,owner_address(orsimulate: trueto probe with the burn address). - MCP validates the request against policy and calls Sera
POST /swap/quote. - MCP returns
uuid+route_params(the exact EIP-712Intentstruct) + caches the binding. - Wallet signs
route_paramsunder the Sera EIP-712 domain:
``js 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); ``
- Agent calls
sera.execute_swapwith{ 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_TOOLSflag — 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 manager —
sera.approval_statusfor 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](src/cli.ts).
Add --json to any command to get raw JSON for piping into jq / scripts.
License
MIT
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: sera-cx
- Source: sera-cx/sera-mcp
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.