StableLens
Developer integrationMCP 2024-11-05

MCP Quickstart

Integration guide for the StableLens MCP endpoint — read-only stablecoin and yield risk data for the AI agents you build. The walk-through below uses one illustrative use case: “a developer agent managing a $1M USDC treasury, alerting on better-fit yield pools that meet the following criteria.”

Prerequisites

  • An API key — provision one on any tier at /pricing, or skip and use x402 micropayments below.
  • An MCP-aware client (Anthropic Claude, OpenAI Responses API, custom — any client that can POST JSON-RPC to an HTTP endpoint).

TypeScript

Pass STABLELENS_API_KEY in the environment. The mcpCall() helper is left as an exercise — it’s a thin wrapper around fetch().

typescript — 1. initialize
// 1. Initialize MCP session
const res = await fetch('https://mcp.stablelens.com', {
  method: 'POST',
  headers: {
    'x-api-key': process.env.STABLELENS_API_KEY!,
    'content-type': 'application/json',
  },
  body: JSON.stringify({
    jsonrpc: '2.0',
    id: 1,
    method: 'initialize',
    params: { protocolVersion: '2024-11-05' },
  }),
});
const { result } = await res.json();
console.log(result.serverInfo);
// → { name: "stablelens", version: "0.1.0" }
typescript — 2. list tools
// 2. List the tool surface
const list = await mcpCall('tools/list');
console.log(list.tools.map(t => t.name));
// → ["get_pool_risk_score", "find_pools_matching", ...]
typescript — 3. find pools
// 3. Find pools matching your agent's allocation rules
const matches = await mcpCall('tools/call', {
  name: 'find_pools_matching',
  arguments: {
    compliance_grade_min: 'A-',
    chain_in: ['ethereum', 'base', 'arbitrum'],
    yield_min_bps: 450,        // 4.5% APY floor
    tvl_usd_min: 50_000_000,   // $50M+ TVL
    capacity_usd_min: 5_000_000, // $5M+ exit capacity
    limit: 25,
  },
});
const pools = JSON.parse(matches.content[0].text).pools;
console.log(`Found ${pools.length} pools matching your criteria`);
typescript — 4. analyze a move
// 4. Decision-support: should your agent move $1M from current → top match?
const move = await mcpCall('tools/call', {
  name: 'analyze_capital_move',
  arguments: {
    from_pool_id: currentPoolId,
    to_pool_id: pools[0].pool_id,
    amount_usd: 1_000_000,
    from_chain: 'ethereum',
    to_chain: pools[0].chain,
  },
});
const analysis = JSON.parse(move.content[0].text);
if (analysis.recommendation === 'favorable') {
  // ... your agent executes the move via its OWN custodial / signing layer.
  // StableLens never signs or executes — we just inform the decision.
}
typescript — 5. standing webhook
// 5. Standing webhook — fire whenever a better-fit pool appears
await mcpCall('tools/call', {
  name: 'register_criteria_rule',
  arguments: {
    name: 'my-treasury-rule-v1',
    criteria: {
      compliance_grade_min: 'A-',
      yield_min_bps_above_chain_median: 50,
      tvl_usd_min: 50_000_000,
      capacity_usd_min: 5_000_000,
    },
    delivery: {
      channel: 'webhook',
      endpoint: 'https://my-agent.example.com/stablelens/match',
    },
  },
});
// Webhook fires within 60s of any matching pool snapshot.
// Team+ tier: HMAC-SHA256 signed; replay endpoint for audit.

Python

python
import os, requests

API_KEY = os.environ["STABLELENS_API_KEY"]
ENDPOINT = "https://mcp.stablelens.com"

def mcp(method: str, params: dict | None = None):
    r = requests.post(
        ENDPOINT,
        headers={"x-api-key": API_KEY, "content-type": "application/json"},
        json={"jsonrpc": "2.0", "id": 1, "method": method, **({"params": params} if params else {})},
        timeout=10,
    )
    r.raise_for_status()
    return r.json()["result"]

# 1. Discover the surface
print(mcp("tools/list")["tools"])

# 2. Find pools matching your allocation rules
matches = mcp("tools/call", {
    "name": "find_pools_matching",
    "arguments": {
        "compliance_grade_min": "A-",
        "chain_in": ["ethereum", "base", "arbitrum"],
        "yield_min_bps": 450,
        "tvl_usd_min": 50_000_000,
        "limit": 25,
    },
})
import json
pools = json.loads(matches["content"][0]["text"])["pools"]
print(f"Found {len(pools)} pools")

curl (any language)

shell
curl -X POST https://mcp.stablelens.com \
  -H "x-api-key: $STABLELENS_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "find_pools_matching",
      "arguments": {
        "compliance_grade_min": "A-",
        "chain_in": ["ethereum", "base", "arbitrum"],
        "yield_min_bps": 450,
        "tvl_usd_min": 50000000,
        "limit": 25
      }
    }
  }'

x402 — pay per call, no signup

For ad-hoc usage, skip the API key entirely and pay per call via the x402 protocol. Settled in USDC on Base.

shell — x402 flow
# x402 micropayment — no API key required.
# 1. Send the request unauthenticated.
# 2. Server returns HTTP 402 with a payment envelope.
# 3. Sign + return a transfer authorization.
# 4. Server validates via x402 facilitator; the call proceeds.

curl -X POST https://mcp.stablelens.com \
  -H "content-type: application/json" \
  -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/call",
        "params": { "name": "get_pool_risk_score",
                    "arguments": { "pool_id": "aave-v3-ethereum-usdc" } } }'

# → HTTP/1.1 402 Payment Required
# → x-payment-required: { "x402_version": 1, "accepts": [ ... ] }

What StableLens does NOT do

We never custody, sign, or execute. The analyze_capital_move response gives the agent the inputs to a decision — gas, bridge fee, yield delta, risk + compliance grade deltas, recommendation, confidence. The agent (or its owner) executes the move via its own signing layer. This boundary is deliberate; see Why read-only? for the regulatory rationale.

Need help integrating? agents@stablelens.com. Questions about the methodology? methodology v2.0.