#!/usr/bin/env python3
"""AIKIT by Trading Checkup - MCP stdio package (v0.1.0). One file, Python 3.8+, standard library only.
Gives your AI assistant sourced, dated exchange facts and trading-bot code checks while it builds a bot. Information only, not financial advice.
Settings (environment):  AIKIT_KEY = your key (akt_...). Empty = the package asks for a free trial key (25 credits, no sign-up)
                         and saves it in ~/.config/aikit/key .   AIKIT_URL = endpoint (default https://api.tradingcheckup.com/aikit/mcp)
Extra local tool: check_bot_file(path) reads a bot file from your project and sends it to check_bot_code (5 credits).
Your code is only sent when a check tool is called; it is checked in memory and not stored."""
import json, os, sys, urllib.request, urllib.error, urllib.parse

URL = os.environ.get("AIKIT_URL", "https://api.tradingcheckup.com/aikit/mcp")
_u = urllib.parse.urlsplit(URL); TRIAL_URL = f"{_u.scheme}://{_u.netloc}/v1/aikit/trial"
KEYFILE = os.path.expanduser(os.environ.get("AIKIT_KEYFILE", "~/.config/aikit/key"))
KEY = os.environ.get("AIKIT_KEY", "").strip()
LOCAL = [{"name": "check_bot_file", "title": "Review / audit a bot file on this computer",
          "description": "5 credits. Code review of a trading-bot file already in this project (.py, .pine, .mq5): reads the file and runs the check_bot_code rule checker on it, so you do not have to paste the code. Use when asked to review or audit a bot file.",
          "inputSchema": {"type": "object", "properties": {"path": {"type": "string"}, "venue": {"type": "string"}}, "required": ["path"], "additionalProperties": False},
          "annotations": {"readOnlyHint": True, "destructiveHint": False, "idempotentHint": True, "openWorldHint": False}}]


def key():
    global KEY
    if KEY: return KEY
    try:
        KEY = open(KEYFILE).read().strip()
        if KEY: return KEY
    except Exception: pass
    try:
        r = json.loads(urllib.request.urlopen(urllib.request.Request(TRIAL_URL, data=b"{}", headers={"Content-Type": "application/json", "User-Agent": "aikit-mcp/0.1"}), timeout=20).read())
        KEY = r.get("key", "")
        if KEY:
            os.makedirs(os.path.dirname(KEYFILE), exist_ok=True); open(KEYFILE, "w").write(KEY); os.chmod(KEYFILE, 0o600)
    except Exception as e:
        print("[aikit] could not get a free trial key:", e, file=sys.stderr)
    return KEY


def post(msg):
    h = {"Content-Type": "application/json", "Accept": "application/json", "User-Agent": "aikit-mcp/0.1"}
    k = key() if msg.get("method") == "tools/call" else (KEY or "")
    if k: h["Authorization"] = "Bearer " + k
    try:
        r = urllib.request.urlopen(urllib.request.Request(URL, data=json.dumps(msg).encode(), headers=h), timeout=60); b = r.read()
        return json.loads(b) if b else None
    except urllib.error.HTTPError as e:
        try: return json.loads(e.read())
        except Exception: return {"jsonrpc": "2.0", "id": msg.get("id"), "error": {"code": -32603, "message": f"AIKIT server answered HTTP {e.code}"}}
    except Exception as e:
        return {"jsonrpc": "2.0", "id": msg.get("id"), "error": {"code": -32603, "message": "cannot reach AIKIT: " + str(e)[:120]}}


def main():
    for line in sys.stdin:
        line = line.strip()
        if not line: continue
        try: msg = json.loads(line)
        except Exception: continue
        if not isinstance(msg, dict) or "id" not in msg: continue
        p = msg.get("params") or {}
        if msg.get("method") == "tools/call" and p.get("name") == "check_bot_file":
            a = p.get("arguments") or {}
            try: code = open(str(a.get("path")), encoding="utf-8", errors="replace").read()[:200_000]
            except Exception as e:
                r = {"jsonrpc": "2.0", "id": msg["id"], "result": {"content": [{"type": "text", "text": "could not read the file: " + str(e)[:150]}], "isError": True}}
            else:
                r = post({"jsonrpc": "2.0", "id": msg["id"], "method": "tools/call", "params": {"name": "check_bot_code",
                          "arguments": {"code": code, "filename": os.path.basename(str(a.get("path"))), **({"venue": a["venue"]} if a.get("venue") else {})}}})
        else:
            r = post(msg)
            if msg.get("method") == "tools/list" and isinstance(r, dict) and isinstance(r.get("result"), dict):
                r["result"]["tools"] = list(r["result"].get("tools") or []) + LOCAL
        if r is not None: sys.stdout.write(json.dumps(r, ensure_ascii=False) + "\n"); sys.stdout.flush()


if __name__ == "__main__": main()
