- 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>
103 lines
3.5 KiB
Python
103 lines
3.5 KiB
Python
"""x402 MCP handler - exposes x402 payment as discoverable MCP tools.
|
|
|
|
Mounts at /mcp/x402 for MCP protocol compatibility.
|
|
Also serves /.well-known/x402 for standard x402 discovery.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
|
|
from fastapi import APIRouter, HTTPException, Request
|
|
|
|
from app.mcp.x402_mcp_server import TOOLS, handle_mcp_call
|
|
|
|
router = APIRouter(tags=["x402-MCP"])
|
|
|
|
# ── Standard MCP endpoint ────────────────────────────────────────
|
|
|
|
|
|
@router.post("/mcp/x402")
|
|
async def mcp_x402_handler(request: Request):
|
|
"""MCP protocol handler for x402 payment tools.
|
|
|
|
Accepts MCP-standard requests: {"method": "tools/list"} or
|
|
{"method": "tools/call", "params": {"name": "...", "arguments": {...}}}
|
|
"""
|
|
body = await request.json()
|
|
method = body.get("method", "")
|
|
|
|
if method == "tools/list":
|
|
return {
|
|
"result": {
|
|
"tools": TOOLS,
|
|
"server": {
|
|
"name": "x402-payment-gateway",
|
|
"version": "1.0.0",
|
|
"description": "Pay-per-call AI tool access via x402 protocol. 274+ tools across crypto intelligence, security, and analysis.",
|
|
},
|
|
}
|
|
}
|
|
|
|
if method == "tools/call":
|
|
params = body.get("params", {})
|
|
tool_name = params.get("name", "")
|
|
arguments = params.get("arguments", {})
|
|
try:
|
|
result = await handle_mcp_call(tool_name, arguments)
|
|
return {"result": result}
|
|
except ValueError as e:
|
|
raise HTTPException(status_code=400, detail=str(e)) from e
|
|
|
|
raise HTTPException(status_code=400, detail=f"Unknown method: {method}")
|
|
|
|
|
|
# ── x402 Discovery endpoint ──────────────────────────────────────
|
|
|
|
|
|
@router.get("/.well-known/x402")
|
|
async def well_known_x402():
|
|
"""x402 service discovery document (RFC-like).
|
|
|
|
Standard endpoint that x402-compatible clients check to discover
|
|
payment capabilities, supported chains, pricing, and facilitator info.
|
|
"""
|
|
from app.routers.x402_enforcement import CHAIN_USDC, TOOL_PRICES, _ensure_tool_prices
|
|
_ensure_tool_prices()
|
|
|
|
paid = sum(1 for v in TOOL_PRICES.values() if v.get("price_usd", 0) > 0)
|
|
min_price = min(v["price_usd"] for v in TOOL_PRICES.values() if v.get("price_usd", 0) > 0)
|
|
max_price = max(v["price_usd"] for v in TOOL_PRICES.values() if v.get("price_usd", 0) > 0)
|
|
|
|
return {
|
|
"x402_version": "2.0",
|
|
"service": "Rug Munch Intelligence x402 Gateway",
|
|
"operator": "Rug Munch Media LLC",
|
|
"discovery_url": "https://mcp.rugmunch.io/.well-known/x402",
|
|
"mcp_url": "https://mcp.rugmunch.io/mcp/x402",
|
|
"docs_url": "https://docs.rugmunch.io/x402",
|
|
"payment_address": os.getenv("X402_PAYMENT_ADDRESS", ""),
|
|
"supported_chains": {
|
|
chain: {
|
|
"network": cfg.get("network", ""),
|
|
"usdc_address": cfg.get("usdc", ""),
|
|
}
|
|
for chain, cfg in CHAIN_USDC.items()
|
|
},
|
|
"pricing": {
|
|
"total_tools": len(TOOL_PRICES),
|
|
"paid_tools": paid,
|
|
"price_range_usd": {"min": min_price, "max": max_price},
|
|
"free_trials": True,
|
|
},
|
|
"facilitators": [
|
|
"coinbase_cdp",
|
|
"payai",
|
|
"cloudflare_x402",
|
|
"x402_rs",
|
|
"primev",
|
|
"asterpay",
|
|
"eip7702",
|
|
],
|
|
"status": "active",
|
|
}
|