rmi-backend/app/databus/free_mcp_servers.py
opencode c762564d40 style(rmi-backend): complete lint cleanup — 1175→0 ruff errors
- Fix 71 invalid-syntax files (class-body newline-broken assignments)
- Add from/None chain to 307 B904 raise-without-from sites
- Add B008 ignore to ruff.toml (already in pyproject.toml)
- Noqa F401 on __init__.py re-exports (137 sites)
- Noqa E402 on deferred imports (63 sites)
- Bulk-add stdlib/FastAPI/project imports for F821 (127 sites)
- Replace ×→x, –→-, …→... in docstrings (4093 chars)
- Manual refactor of 5 SIM103/SIM116 patterns

Tests: 791 passed (66 deselected due to pre-existing Redis issues in test_rag.py)
Co-authored-by: opencode <opencode@rugmunch.io>
2026-07-06 15:43:20 +02:00

247 lines
10 KiB
Python

"""
RMI Free MCP Servers - 5 high-value tools to attract bots → x402 revenue funnel.
Each server: generous free tier → rate limit → x402 pay-per-call upgrade.
Listed on Smithery, Glama, mcp.so for maximum discoverability.
"""
import json
import os
from app.core.redis import get_redis
from app.routers.x402_databus_tools import check_trial
# ═══════════════════════════════════════════════════
# SHARED: Redis + x402 trial tracker
# ═══════════════════════════════════════════════════
# MCP #1: CRYPTO NEWS - 500+ sources, sentiment-scored
# ═══════════════════════════════════════════════════
def search_news(query: str, limit: int = 10, fingerprint: str = "anon") -> dict:
"""Search 500+ crypto news sources. 20 free calls/day."""
auth = check_trial(fingerprint, "news", 20)
if auth.get("tier") == "free_exhausted":
return {"error": "Free tier exhausted", "upgrade": auth["upgrade"]}
r = get_redis()
results = []
q = query.lower()
for idx in ["rmi:news:500feeds", "rmi:news:index", "rmi:news:global:index"]:
for aid in r.zrevrange(idx, 0, -1):
a = json.loads(r.get(f"rmi:news:article:{aid}") or "{}")
if q in a.get("title", "").lower():
results.append(
{
"title": a["title"],
"source": a.get("source", ""),
"date": a.get("ingested_at", 0),
}
)
if len(results) >= limit:
return {
"query": query,
"results": results,
"total_sources": 500,
"auth": auth,
"mcp": "rmi-news",
}
return {
"query": query,
"results": results,
"total_sources": 500,
"auth": auth,
"mcp": "rmi-news",
}
# ═══════════════════════════════════════════════════
# MCP #2: WALLET INTELLIGENCE - 10M+ labels, 13 chains
# ═══════════════════════════════════════════════════
def resolve_wallet(address: str, fingerprint: str = "anon") -> dict:
"""Resolve any crypto address across 13 chains. 15 free/day."""
auth = check_trial(fingerprint, "wallet", 15)
if auth.get("tier") == "free_exhausted":
return {"error": "Free tier exhausted", "upgrade": auth["upgrade"]}
r = get_redis()
addr = address.lower()
# Check Postgres wallet_labels
from dotenv import load_dotenv
load_dotenv("/app/.env", override=True)
import psycopg2
result = {"address": address, "labels": [], "chains_found": []}
try:
pg = psycopg2.connect(
host="rmi-postgres",
port=5432,
user="rmi",
password=os.getenv("POSTGRES_PASSWORD"),
dbname="rmi",
)
cur = pg.cursor()
cur.execute(
"SELECT chain, label, name_tag FROM wallet_labels WHERE address = %s LIMIT 5", (addr,)
)
for chain, label, tag in cur.fetchall():
result["labels"].append({"chain": chain, "label": label, "entity": tag})
result["chains_found"].append(chain)
cur.close()
pg.close()
except Exception:
pass
# Also check Redis cache
for chain in ["ethereum", "solana", "bsc", "polygon"]:
cached = r.get(f"rmi:label:{chain}:{addr}")
if cached:
c = json.loads(cached)
if {
"chain": chain,
"label": c.get("label", ""),
"entity": c.get("name_tag", ""),
} not in result["labels"]:
result["labels"].append(
{"chain": chain, "label": c.get("label", ""), "entity": c.get("name_tag", "")}
)
result["total_label_db"] = "10M+ addresses (MBAL + eth-labels + Chainabuse)"
result["auth"] = auth
result["mcp"] = "rmi-wallet-intel"
return result
# ═══════════════════════════════════════════════════
# MCP #3: TOKEN SECURITY - Rug pull, honeypot, scam
# ═══════════════════════════════════════════════════
def scan_token(address: str, chain: str = "ethereum", fingerprint: str = "anon") -> dict:
"""Security scan any token. 10 free/day. Premium: $0.02/call."""
auth = check_trial(fingerprint, "security", 10)
if auth.get("tier") == "free_exhausted":
return {"error": "Free tier exhausted", "upgrade": auth["upgrade"]}
import httpx as req
result = {"address": address, "chain": chain, "checks": {}}
# Chainabuse check
try:
r = req.get(f"https://api.chainabuse.com/v0/reports?address={address}", timeout=5)
if r.status_code == 200:
reports = r.json().get("reports", [])
result["checks"]["chainabuse_reports"] = len(reports)
result["checks"]["known_scam"] = len(reports) > 0
except Exception:
pass
# GoPlus security check (free, no key)
try:
r = req.get(
f"https://api.gopluslabs.io/api/v1/token_security/{chain}?contract_addresses={address}",
timeout=10,
)
if r.status_code == 200:
data = r.json().get("result", {}).get(address.lower(), {})
result["checks"]["honeypot"] = data.get("is_honeypot") == "1"
result["checks"]["buy_tax"] = data.get("buy_tax", "0")
result["checks"]["sell_tax"] = data.get("sell_tax", "0")
result["checks"]["liquidity"] = data.get("lp_holders", [])
except Exception:
pass
result["auth"] = auth
result["mcp"] = "rmi-token-security"
return result
# ═══════════════════════════════════════════════════
# MCP #4: CROSS-CHAIN BRIDGE MONITOR
# ═══════════════════════════════════════════════════
def check_bridge_transfers(
address: str = "", bridge: str = "wormhole", fingerprint: str = "anon"
) -> dict:
"""Check cross-chain bridge activity. 10 free/day."""
auth = check_trial(fingerprint, "bridge", 10)
if auth.get("tier") == "free_exhausted":
return {"error": "Free tier exhausted", "upgrade": auth["upgrade"]}
import httpx as req
bridges = {
"wormhole": "https://wormholescan.io/api/v1/operations",
"layerzero": "https://layerzeroscan.com/api",
}
url = bridges.get(bridge, bridges["wormhole"])
result = {"bridge": bridge, "address": address, "transfers": []}
try:
r = req.get(f"{url}?address={address}&limit=5" if address else f"{url}/stats", timeout=10)
if r.status_code == 200:
result["data"] = r.json()
except Exception:
pass
result["supported_bridges"] = list(bridges.keys())
result["auth"] = auth
result["mcp"] = "rmi-bridge-monitor"
return result
# ═══════════════════════════════════════════════════
# MCP #5: DEFI ANALYTICS - TVL, yields, protocols
# ═══════════════════════════════════════════════════
def defi_analytics(protocol: str = "", chain: str = "", fingerprint: str = "anon") -> dict:
"""DeFi TVL, yields, protocol health. 20 free/day. Premium: $0.01/call."""
auth = check_trial(fingerprint, "defi", 20)
if auth.get("tier") == "free_exhausted":
return {"error": "Free tier exhausted", "upgrade": auth["upgrade"]}
import httpx as req
result = {"protocol": protocol, "chain": chain}
try:
r = req.get(
f"https://api.llama.fi/protocol/{protocol}"
if protocol
else "https://api.llama.fi/protocols",
timeout=10,
)
if r.status_code == 200:
result["tvl_data"] = r.json()
result["source"] = "DeFiLlama (free, unlimited)"
except Exception:
pass
# Pyth price feed
try:
r = req.get(
"https://hermes.pyth.network/api/latest_price_feeds?ids[]=0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace",
timeout=5,
)
if r.status_code == 200:
p = r.json()[0]["price"]
result["eth_price"] = float(p["price"]) * (10 ** float(p["expo"]))
result["price_source"] = "Pyth Network (125+ institutional publishers)"
except Exception:
pass
result["auth"] = auth
result["mcp"] = "rmi-defi-analytics"
return result
# MCP Server registry
MCP_TOOLS = {
"rmi-news": {
"search": search_news,
"description": "500+ source crypto news, 20 free/day",
"price": 0.01,
},
"rmi-wallet-intel": {
"resolve": resolve_wallet,
"description": "10M+ labeled addresses, 15 free/day",
"price": 0.02,
},
"rmi-token-security": {
"scan": scan_token,
"description": "Rug pull + honeypot detection, 10 free/day",
"price": 0.02,
},
"rmi-bridge-monitor": {
"check": check_bridge_transfers,
"description": "Cross-chain bridge monitoring, 10 free/day",
"price": 0.01,
},
"rmi-defi-analytics": {
"analyze": defi_analytics,
"description": "DeFi TVL + yields, 20 free/day",
"price": 0.01,
},
}