merge: chore/cleanup-remove-bloat-and-secrets into main

This commit is contained in:
Crypto Rug Munch 2026-07-02 01:24:22 +07:00
commit bde2f3a97d
1173 changed files with 437609 additions and 0 deletions

325
app/routers/mcp_proxy.py Normal file
View file

@ -0,0 +1,325 @@
"""
Local MCP Server Proxy makes free local MCP servers accessible via REST API.
Reads tool definitions from MCP server manifests and proxies tool calls.
Local servers run via stdio we spawn them on demand with a process cache.
All data is FREE to call (no API keys, just local compute/RPC queries).
"""
import asyncio
import json
import subprocess
import time
SERVER_REGISTRY = {
"feargreed": {
"name": "Crypto Fear & Greed Index",
"path": "/root/.hermes/mcp-servers/crypto-feargreed-mcp",
"command": ["python3", "main.py"],
"tools": [
{
"id": "feargreed_get_index",
"name": "Get Fear & Greed Index",
"description": "Current crypto Fear & Greed Index value and classification",
},
{
"id": "feargreed_get_historical",
"name": "Get Historical Fear & Greed",
"description": "Historical Fear & Greed values for a date range",
},
],
},
"crypto-news": {
"name": "Crypto News API",
"path": "/root/.hermes/mcp-servers/crypto-news-api",
"command": ["node", "dist/index.js"],
"tools": [
{
"id": "news_get_latest",
"name": "Get Latest News",
"description": "Real-time crypto news from 12+ sources with AI sentiment",
},
{
"id": "news_search",
"name": "Search News",
"description": "Search crypto news by keyword, source, or date range",
},
{
"id": "news_sentiment",
"name": "News Sentiment",
"description": "Aggregated market sentiment from news sources",
},
],
},
"indicators": {
"name": "Crypto Indicators",
"path": "/root/.hermes/mcp-servers/crypto-indicators-mcp",
"command": ["node", "dist/index.js"],
"tools": [
{
"id": "indicators_rsi",
"name": "RSI Indicator",
"description": "Relative Strength Index for any token",
},
{
"id": "indicators_macd",
"name": "MACD Indicator",
"description": "Moving Average Convergence Divergence",
},
{
"id": "indicators_bollinger",
"name": "Bollinger Bands",
"description": "Bollinger Bands volatility indicator",
},
{"id": "indicators_ema", "name": "EMA", "description": "Exponential Moving Average"},
{"id": "indicators_sma", "name": "SMA", "description": "Simple Moving Average"},
],
},
"evmscope": {
"name": "EVMScope Intelligence",
"path": "/root/.hermes/mcp-servers/evmscope",
"command": ["node", "dist/index.js"],
"tools": [
{
"id": "evmscope_token_price",
"name": "Token Price",
"description": "Current token price across chains",
},
{
"id": "evmscope_token_info",
"name": "Token Info",
"description": "Token metadata — name, symbol, decimals, supply",
},
{
"id": "evmscope_token_holders",
"name": "Token Holders",
"description": "Token holder distribution and top holders",
},
{
"id": "evmscope_honeypot",
"name": "Honeypot Check",
"description": "Check if a token is a honeypot scam",
},
{
"id": "evmscope_whale_movements",
"name": "Whale Movements",
"description": "Recent large transactions for a token",
},
{
"id": "evmscope_gas_price",
"name": "Gas Price",
"description": "Current gas prices across chains",
},
{
"id": "evmscope_portfolio",
"name": "Portfolio",
"description": "Wallet portfolio with balances across chains",
},
{
"id": "evmscope_bridge_routes",
"name": "Bridge Routes",
"description": "Optimal bridge routes between chains",
},
{
"id": "evmscope_yield_rates",
"name": "Yield Rates",
"description": "Current DeFi yield rates across protocols",
},
{
"id": "evmscope_swap_quote",
"name": "Swap Quote",
"description": "Best swap quote across DEX aggregators",
},
{
"id": "evmscope_nft_info",
"name": "NFT Info",
"description": "NFT metadata and collection info",
},
{
"id": "evmscope_contract_abi",
"name": "Contract ABI",
"description": "Fetch verified contract ABI",
},
{
"id": "evmscope_decode_tx",
"name": "Decode Transaction",
"description": "Decode raw transaction data",
},
],
},
"polymarket": {
"name": "Polymarket Data",
"path": "/root/.hermes/mcp-servers/graph-polymarket-mcp",
"command": ["node", "dist/index.js"],
"tools": [
{
"id": "polymarket_active_markets",
"name": "Active Markets",
"description": "Currently active prediction markets",
},
{
"id": "polymarket_market_detail",
"name": "Market Detail",
"description": "Detailed market data — prices, volume, liquidity",
},
{
"id": "polymarket_orderbook",
"name": "Orderbook",
"description": "Live orderbook for a market",
},
{
"id": "polymarket_open_interest",
"name": "Open Interest",
"description": "Open interest across markets",
},
{
"id": "polymarket_traders",
"name": "Top Traders",
"description": "Top traders by volume/profit",
},
],
},
"prediction-markets": {
"name": "Prediction Markets",
"path": "/root/.hermes/mcp-servers/prediction-market-mcp",
"command": ["node", "dist/index.js"],
"tools": [
{
"id": "predmkt_polymarket",
"name": "Polymarket Data",
"description": "Polymarket markets, prices, and events",
},
{
"id": "predmkt_kalshi",
"name": "Kalshi Data",
"description": "Kalshi prediction market data",
},
{
"id": "predmkt_predictit",
"name": "PredictIt Data",
"description": "PredictIt market data",
},
],
},
"web3-research": {
"name": "Web3 Research",
"path": "/root/.hermes/mcp-servers/web3-research-mcp",
"command": ["node", "dist/index.js"],
"tools": [
{
"id": "research_coingecko",
"name": "CoinGecko Research",
"description": "Deep CoinGecko data — prices, markets, exchanges",
},
{
"id": "research_defillama",
"name": "DeFiLlama Research",
"description": "Protocol TVL, yields, chain metrics from DeFiLlama",
},
{
"id": "research_combined",
"name": "Combined Research",
"description": "Multi-source research combining CoinGecko + DeFiLlama",
},
],
},
"jupiter": {
"name": "Jupiter DEX",
"path": "/root/.hermes/mcp-servers/jupiter-mcp",
"command": ["node", "dist/index.js"],
"tools": [
{
"id": "jupiter_quote",
"name": "Swap Quote",
"description": "Best swap route and price quote on Solana",
},
{
"id": "jupiter_price",
"name": "Token Price",
"description": "Current token price via Jupiter aggregator",
},
{
"id": "jupiter_token_list",
"name": "Token List",
"description": "All verified tokens on Jupiter",
},
],
},
}
# Process cache — keep server processes alive for 5 min
_proc_cache: dict[str, tuple[subprocess.Popen, float]] = {}
_CACHE_TTL = 300 # 5 minutes
async def _get_or_spawn(server_id: str):
"""Get or spawn an MCP server process."""
if server_id not in SERVER_REGISTRY:
return None
now = time.time()
if server_id in _proc_cache:
proc, created = _proc_cache[server_id]
if now - created < _CACHE_TTL and proc.poll() is None:
return proc
cfg = SERVER_REGISTRY[server_id]
try:
proc = subprocess.Popen(
cfg["command"],
cwd=cfg["path"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
_proc_cache[server_id] = (proc, now)
# Give it a moment to initialize
await asyncio.sleep(1)
return proc
except Exception:
return None
async def call_local_mcp(server_id: str, tool_name: str, params: dict | None = None) -> dict:
"""Call a tool on a local MCP server."""
proc = await _get_or_spawn(server_id)
if not proc:
return {"error": f"Server '{server_id}' not available"}
# MCP JSON-RPC call
request = {
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": tool_name,
"arguments": params or {},
},
}
try:
proc.stdin.write((json.dumps(request) + "\n").encode())
proc.stdin.flush()
# Read response line
line = proc.stdout.readline()
result = json.loads(line.decode())
if "error" in result:
return {"error": result["error"]}
return {"result": result.get("result", result)}
except Exception as e:
return {"error": str(e)}
def get_local_mcp_tools() -> list[dict]:
"""Get all available local MCP tools."""
tools = []
for server_id, cfg in SERVER_REGISTRY.items():
for tool in cfg["tools"]:
tools.append(
{
"server": server_id,
"server_name": cfg["name"],
**tool,
}
)
return tools