Writing

Uniswap MCP Server — Giving AI Agents Direct Access to On-Chain Data

I built a Model Context Protocol (MCP) server that connects any MCP-compatible AI client directly to Uniswap. Once it's running, a model can query token prices, inspect liquidity pools, get swap quotes, and even execute trades — without any custom integration code on the client side.

The Problem

AI agents live in a closed world. To answer questions about Uniswap — "what's the current price of WETH?" or "is there more liquidity in the 0.05% or 0.3% WETH/USDC pool?" — a model needs data. The usual answer is a hand-rolled RAG pipeline or a custom API wrapper that goes stale.

The Model Context Protocol is a standardized way to give models exactly the tools they need. This server implements it using the FastMCP framework, so any MCP client (Claude Desktop, Cursor, or a custom agent) picks up the tools instantly from a single config line.

Two Modes

The server runs in two modes:

  • Read-only — query token info, pool data, and swap quotes. No private key required.
  • Read-write — everything above, plus on-chain swap execution. Requires a funded wallet private key.

The network is detected automatically from the chain_id the RPC endpoint reports. Point it at Ethereum, Polygon, Optimism, or Arbitrum — all V2 and V3 contract addresses are hardcoded per network and validated at startup.

The Tools

The model gets seven callable tools:

ToolWhat it does
get_token_infoERC-20 metadata (name, symbol, decimals, supply)
get_token_priceReal-time USD price derived from on-chain V3 pool data
get_v3_poolFull V3 pool state — liquidity, sqrt price, current tick
get_v2_pairV2 reserves and implied price
get_pool_by_addressV3 pool state by address directly
get_swap_quoteSimulated quote via the on-chain Quoter — no transaction
execute_swapExecutes a real swap through the V3 router

The pricing logic is the interesting part. get_token_price doesn't call any off-chain price oracle. It walks the token's actual V3 pools against USDC, USDT, and WETH across the three fee tiers (500, 3000, 10000 bps) and returns the first valid price it finds:

# walks USDC, USDT, WETH quote pools across fee tiers
# and returns the first valid USD price for a token

Resources and Prompts

Beyond tools, the server exposes MCP resources — read-only data a model can fetch mid-conversation:

  • protocol://addresses — canonical V2/V3 factory, quoter, router, WETH, USDC, and USDT addresses for the connected chain
  • network://status — chain ID and latest block

And two prompts that guide the model through multi-step workflows:

  • analyze_token — fetches addresses, reads the USD price, inspects the V3 pool, and synthesizes a report
  • execute_trade — a confirmation-gated swap flow: quote first, present it to the user, and only execute after explicit approval

The execute_trade prompt is a deliberate safety design. The model can't fire a swap on its own — it must show the quote and get confirmation, which keeps live trading human-gated.

Swap Execution

execute_swap sends a real transaction through the V3 router. Details that matter in production:

  • The router is auto-approved — if the current token allowance is insufficient, it grants one and proceeds
  • Slippage defaults to 50 bps (0.5%) and is configurable per call
  • A deadline in minutes from now protects against long-mempool transactions
  • If no private key is configured, the tool returns a clear error instead of failing silently

Testing

The suite runs fully offline — every blockchain call is mocked. It covers 204 tests across configuration, address validation, ABI loading, every contract wrapper, the UniswapClient, and each tool, resource, and prompt:

uv run pytest tests/

Setup

Install with uv and point it at any Ethereum-compatible RPC:

uv sync
uv run python server.py

For Claude Desktop, add it as an MCP server and the tools appear in the next conversation:

{
  "mcpServers": {
    "uniswap": {
      "command": "uv",
      "args": ["run", "python", "server.py"],
      "env": { "RPC_URL": "https://mainnet.infura.io/v3/YOUR_PROJECT_ID" }
    }
  }
}

Reflections

The cleanest part of this design is how little glue there is. Because MCP standardizes the interface, I didn't have to build any client integration — one config block and the model has live, on-chain Uniswap data. The tool surface stays small and typed, and the test suite runs without a network, so it's easy to iterate on.

Check it out on GitHub: rakibhossain72/uniswap-mcp-server