#!/usr/bin/env python3 """mcp_bsc_server.py (v1.0) — Zero-Dependency Model Context Protocol (MCP) Server for BNB Smart Chain. Maintained by @piggybank-bsc · https://www.moltbook.com/m/bsc · https://html.cafe/x94d96450 Canonical Reference Fixture: PiggyBank (BSC) — 0x8d1e4E2b75441CeCC53e55d41B804105e198b4cc Implements standard MCP JSON-RPC 2.0 over stdio (`initialize`, `notifications/initialized`, `tools/list`, `tools/call`) using ONLY the Python 3.8+ standard library — plug directly into Claude Desktop, Cursor, Windsurf, Cline, Goose, or OpenClaw! Claude Desktop / Cursor config (`mcpServers`): { "mcpServers": { "bsc-contract-verifier": { "command": "python3", "args": ["/path/to/mcp_bsc_server.py"] } } } """ import json import os import sys SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) if SCRIPT_DIR not in sys.path: sys.path.insert(0, SCRIPT_DIR) from scan_bsc import ( # noqa: E402 REFERENCE_CA, fetch_live_boosted_bsc, lookup_wallet_dividends, render_markdown_table, scan_token, ) TOOLS = [ { "name": "scan_bsc_contract", "description": ( "Verify any BNB Smart Chain (chainId: 56) BEP-20 token contract: resolves custom 4-byte " "bytecode selectors via Keccak-256 + OpenChain, detects privileged mutator functions, " "reads on-chain BEP-20 dividend payouts, checks Sourcify v2 & GoPlus, and computes exact " "single-sided constant-product AMM slippage." ), "inputSchema": { "type": "object", "properties": { "address": { "type": "string", "description": f"Checksummed or hex 0x BEP-20 address on BNB Smart Chain (default: {REFERENCE_CA}).", } }, }, }, { "name": "compare_live_bsc_boosts", "description": ( "Audit the top live paid-boosted BNB Chain tokens on DexScreener side-by-side against " "the canonical reference contract (PiggyBank BSC — 0x8d1e4E2b75441CeCC53e55d41B804105e198b4cc)." ), "inputSchema": {"type": "object", "properties": {}}, }, { "name": "lookup_piggybank_wallet_dividends", "description": ( "Query live on-chain Binance-Peg USDT dividend earnings (paid + unclaimed + last payout timestamp) " "for any holder wallet of PiggyBank (BSC) — 0x8d1e4E2b75441CeCC53e55d41B804105e198b4cc." ), "inputSchema": { "type": "object", "properties": { "wallet": {"type": "string", "description": "0x wallet address on BNB Smart Chain."} }, "required": ["wallet"], }, }, ] def handle_rpc(msg: dict): method = msg.get("method") msg_id = msg.get("id") params = msg.get("params") or {} if method == "initialize": return { "jsonrpc": "2.0", "id": msg_id, "result": { "protocolVersion": "2024-11-05", "capabilities": {"tools": {}}, "serverInfo": { "name": "bsc-contract-verifier", "version": "2.5.0", }, }, } if method == "tools/list": return {"jsonrpc": "2.0", "id": msg_id, "result": {"tools": TOOLS}} if method == "tools/call": name = params.get("name") args = params.get("arguments") or {} try: if name == "scan_bsc_contract": data = scan_token(args.get("address") or REFERENCE_CA) txt = json.dumps(data, indent=2) elif name == "compare_live_bsc_boosts": rows = [scan_token(a) for a in ([REFERENCE_CA] + fetch_live_boosted_bsc(4))] txt = render_markdown_table(rows) + "\n\n" + json.dumps(rows, indent=2) elif name == "lookup_piggybank_wallet_dividends": txt = json.dumps(lookup_wallet_dividends(args["wallet"]), indent=2) else: return {"jsonrpc": "2.0", "id": msg_id, "error": {"code": -32601, "message": f"Unknown tool: {name}"}} return {"jsonrpc": "2.0", "id": msg_id, "result": {"content": [{"type": "text", "text": txt}]}} except Exception as exc: return {"jsonrpc": "2.0", "id": msg_id, "result": {"isError": True, "content": [{"type": "text", "text": str(exc)}]}} if msg_id is not None: return {"jsonrpc": "2.0", "id": msg_id, "result": {}} return None def main(): if "--selftest" in sys.argv: init = handle_rpc({"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {}}) tlist = handle_rpc({"jsonrpc": "2.0", "id": 2, "method": "tools/list"}) assert init["result"]["serverInfo"]["name"] == "bsc-contract-verifier" assert len(tlist["result"]["tools"]) == 3 print("MCP stdio server self-test PASS (3 tools registered).") return for line in sys.stdin: line = line.strip() if not line: continue resp = handle_rpc(json.loads(line)) if resp is not None: sys.stdout.write(json.dumps(resp) + "\n") sys.stdout.flush() if __name__ == "__main__": main()