mcp-opcode

mcp-opcode

MCP server for opcode gasless trading API, enabling agents to perform trades, logins, and account operations through a sign-then-submit flow without holding private keys.

Category
Visit Server

README

mcp-opcode

Python SDK for the opcode gasless trading API, and the MCP server built on top of it. It lets an agent, bot or script do what a user does in the opcode app — over plain HTTP, with its own wallet.

Today this repo holds opcode_sdk. The MCP server lands on top of it.

Design

  • Sign-then-submit. The client never holds a private key. Every signed action is two calls: prepare_X(...) returns the exact EIP-712 / EIP-7702 payload(s) to sign, the caller signs them with whatever custody they have, and submit_X(prepared, sig) POSTs the result. OpcodeClient takes no signer.
  • No EVM RPC. Everything needed to build a signature comes off the quote or the session — the authorization nonce and the approve nonce are both carried in the quote descriptor. The SDK never opens a node connection.
  • Trusted values are pinned, not accepted. Chain id, gateway and approve-delegate are checked against client-side constants before anything is signed, so a compromised backend cannot get a signature over an address of its choosing. See TrustedValues.
  • Guards run before the key is touched. A quote that failed the server's safety verdict, is over the effective cap, or no longer has enough of its submit window left is refused at prepare_order() — not after a signature exists.
  • Typed errors. Every wire error kind maps to an exception class chosen for what the caller should do about it, so retry-vs-fatal is a type, not a string match.
  • Sync first. Built on httpx.Client.

Session token rides in the x-opcode-session header, held in memory only.

Install

uv sync

Usage

from opcode_sdk import OpcodeClient, KeystoreSigner, EnvPassword, WalletKind, TrustedValues

client = OpcodeClient("https://app.opcode.fi", chain_id=1)
signer = KeystoreSigner("wallet.json", EnvPassword("OPCODE_KEYSTORE_PASSWORD"))

prep = client.auth.prepare_login(signer.address)
client.auth.submit_login(prep, signer.sign_typed_data(prep.signable))

quote = client.trade.quote(token_in, token_out, amount_in, wallet=WalletKind.embedded)
order = client.trade.prepare_order(quote, trusted=TrustedValues.mainnet())
sigs = {
    k: (signer.sign_authorization(s) if k == "authorization" else signer.sign_typed_data(s))
    for k, s in order.signables.items()
    if s is not None
}
res = client.trade.submit_order(order, sigs)

OpcodeWallet(client, signer) wraps these into one-call flows (login, accept_terms, trade, wait_for_order) and re-logs in automatically on a 401.

Custody

KeystoreSigner reads a standard V3 eth-keystore and is the default. Two things are hooked separately, so you can replace either without the other:

  • PasswordSource — where the password comes from. EnvPassword, FilePassword, PromptPassword, or your own callable.
  • UnlockGate — whether a given signature is allowed to happen at all. AlwaysUnlocked, ConfirmEachSignature, CachedConfirmation, or your own. The gate is handed a SignRequest describing what is about to be signed, and raises UnlockDenied to refuse.

For any other custody (HSM, remote signer, MPC, hardware) implement the Signer protocol — sign_typed_data and sign_authorization — and pass it anywhere a signer is taken. Nothing in the SDK reaches for a key on its own.

An EIP-7702 authorization is called out as its own SignKind: it delegates the EOA's code and is not something a gasless client can undo, so a gate can treat it differently from an ordinary order signature. CachedConfirmation never caches it.

Surfaces

client.auth, .onboarding, .market, .account, .compliance, .explorer, .trade, .feed, .recipients.

Buys, sells and withdrawals all go through the same quote-and-sign path — a withdrawal is a same-token swap to another receiver. Paying an address other than the signer requires that address to be in the recipient book first (client.recipients), and the book's entries are re-verified locally against your own signature rather than trusted as returned.

Membership and terms status are read from GET /api/session; there are no standalone /invite/status, /terms/status or /session_limits endpoints.

tradable_now() answers whether an asset can be traded right now from the catalog entry plus market status. It is a client-side read of side-collapsed data and cannot see a per-side halt; a quote is the only authority.

Tests

uv run pytest

The suite pins the EIP-712 digests, the order meta bit packing, the grant plan, and the tradability gate. It makes no network calls.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured