HongyiShi commited on
Commit
5bfb623
Β·
1 Parent(s): 3668f9c

allow user input to decide API key in-session

Browse files
Files changed (1) hide show
  1. app.py +84 -58
app.py CHANGED
@@ -1,83 +1,109 @@
1
  """
2
- Gradio Space – Brawl Stars battle-log viewer
3
- Now shows the server’s public IP so you can whitelist it
 
 
4
  """
5
- import os, socket, requests, gradio as gr, brawlstats
 
6
 
 
 
 
 
7
 
8
- # ────────────────────────────────────────────────────────────────
9
- # 0 Utility – discover the IP our outbound requests will use
10
- # ────────────────────────────────────────────────────────────────
11
- def get_public_ip() -> str:
 
12
  """
13
- Try https://api.ipify.org first (tiny plain-text service).
14
- Fall back to http://ifconfig.me or container interface.
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  """
16
- for url in ("https://api.ipify.org", "https://ifconfig.me/ip"):
17
- try:
18
- resp = requests.get(url, timeout=3)
19
- if resp.ok:
20
- return resp.text.strip()
21
- except requests.RequestException:
22
- pass
23
- # last-ditch: internal docker address (may be 10.x/172.x)
24
- return socket.gethostbyname(socket.gethostname())
25
 
26
 
27
- SERVER_IP = get_public_ip()
 
 
 
 
 
28
 
 
29
 
30
- # ────────────────────────────────────────────────────────────────
31
- # 1 Gradio callback
32
- # ────────────────────────────────────────────────────────────────
33
- def recent_battles(api_key: str, player_tag: str) -> dict:
34
- api_key = api_key.strip()
35
- tag = player_tag.strip().upper().lstrip("#")
36
 
37
- if not api_key:
38
- return {"error": "API key is empty!"}
 
 
 
 
 
39
 
 
 
 
 
 
 
 
40
  try:
41
- client = brawlstats.Client(api_key)
42
- logs = client.get_battle_logs(tag)
43
  except brawlstats.Forbidden:
44
  return {"error": "Invalid API key"}
45
  except brawlstats.NotFound:
46
  return {"error": f"Player #{tag} not found"}
47
  except brawlstats.RequestError as e:
48
- return {"error": f"Request failed: {e}"}
49
 
50
  return {
51
- "server_ip": SERVER_IP,
52
- "player": f"#{tag}",
53
- "count": len(logs),
54
- "battles": logs.raw_data
55
  }
56
 
57
 
58
- # ────────────────────────────────────────────────────────────────
59
- # 2 Interface
60
- # ────────────────────────────────────────────────────────────────
61
- with gr.Blocks(title="Brawl Stars – Recent Matches") as demo:
62
- gr.Markdown(
63
- f"### Server public IP: `{SERVER_IP}` \n"
64
- "Add this address to **Allowed IPs** when you generate a Brawl Stars API key."
65
- )
66
-
67
- api_box = gr.Textbox(
68
- label="API Key",
69
- type="password",
70
- placeholder="Paste your API token…"
71
- )
72
- tag_box = gr.Textbox(
73
- label="Player Tag",
74
- placeholder="#V2LQY9UY"
75
- )
76
- out_json = gr.JSON(label="Battle Log")
77
-
78
- api_box.change(lambda *_: None, inputs=None, outputs=out_json)
79
- tag_box.submit(recent_battles, [api_box, tag_box], out_json)
80
 
81
- if __name__ == "__main__":
82
- demo.launch()
 
 
 
83
 
 
 
 
 
 
 
1
  """
2
+ MCP-ready Gradio app
3
+ β€’ Tool 1: save_brawlstars_key(api_key) β†’ str
4
+ β€’ Tool 2: get_recent_battles(player_tag) β†’ dict
5
+ UI: two tabs so humans can still use the app.
6
  """
7
+ import gradio as gr
8
+ import brawlstats # pip install brawlstats
9
 
10
+ # ───────────────────────────────────────────────
11
+ # GLOBAL STATE (shared by all tool invocations)
12
+ # ───────────────────────────────────────────────
13
+ BS_API_KEY = None # will hold the token after Tool-1 runs
14
 
15
+
16
+ # ───────────────────────────────────────────────
17
+ # TOOL 1 – save the key (no echo)
18
+ # ───────────────────────────────────────────────
19
+ def save_brawlstars_key(api_key: str) -> str:
20
  """
21
+ Store a Brawl Stars API key in server memory for later use.
22
+
23
+ This should be the **first** tool called in a session. Once the key
24
+ is saved, subsequent calls to `get_recent_battles` can access the API
25
+ without requiring the LLM (or user) to resend the long token.
26
+
27
+ Args:
28
+ api_key (str): Your personal token generated at
29
+ https://developer.brawlstars.com. Do **not** share this
30
+ publiclyβ€”send it only once via this tool.
31
+
32
+ Returns:
33
+ str: Status message β€”
34
+ β€’ "βœ… API key saved in server memory" on success
35
+ β€’ "❌ No key provided" if the argument was empty
36
  """
37
+ global BS_API_KEY
38
+ BS_API_KEY = api_key.strip()
39
+ if BS_API_KEY:
40
+ return "βœ… API key saved in server memory"
41
+ return "❌ No key provided"
 
 
 
 
42
 
43
 
44
+ # ───────────────────────────────────────────────
45
+ # TOOL 2 – fetch recent battles using saved key
46
+ # ───────────────────────────────────────────────
47
+ def get_recent_battles(player_tag: str) -> dict:
48
+ """
49
+ Retrieve a player's 25 most-recent Brawl Stars battles.
50
 
51
+ Call `save_brawlstars_key` **once** beforehand to cache the API key.
52
 
53
+ Args:
54
+ player_tag (str): The player’s in-game tag, with or without the
55
+ leading '#', e.g. "#V2LQY9UY" or "V2LQY9UY".
 
 
 
56
 
57
+ Returns:
58
+ dict: On success –
59
+ {
60
+ "player": "#TAG",
61
+ "count": <int>, # number of battles returned
62
+ "battles": <list[dict]> # raw JSON from Supercell
63
+ }
64
 
65
+ On failure –
66
+ { "error": "<human-readable message>" }
67
+ """
68
+ if not BS_API_KEY:
69
+ return {"error": "API key not set - call save_brawlstars_key first"}
70
+
71
+ tag = player_tag.strip().upper().lstrip("#")
72
  try:
73
+ client = brawlstats.Client(BS_API_KEY)
74
+ logs = client.get_battle_logs(tag) # BattleLog object
75
  except brawlstats.Forbidden:
76
  return {"error": "Invalid API key"}
77
  except brawlstats.NotFound:
78
  return {"error": f"Player #{tag} not found"}
79
  except brawlstats.RequestError as e:
80
+ return {"error": f"API request failed: {e}"}
81
 
82
  return {
83
+ "player": f"#{tag}",
84
+ "count": len(logs),
85
+ "battles": logs.raw_data # serialisable list
 
86
  }
87
 
88
 
89
+ # ───────────────────────────────────────────────
90
+ # HUMAN-FRIENDLY UI (optional)
91
+ # ───────────────────────────────────────────────
92
+ with gr.Blocks(title="Brawl Stars MCP Tools") as demo:
93
+ with gr.Tab("πŸ”‘ Save API Key"):
94
+ api_box = gr.Textbox(type="password", label="API Key")
95
+ save_btn = gr.Button("Save")
96
+ save_out = gr.Textbox(label="Status", interactive=False)
97
+ save_btn.click(save_brawlstars_key, inputs=api_box, outputs=save_out)
 
 
 
 
 
 
 
 
 
 
 
 
 
98
 
99
+ with gr.Tab("πŸ“œ Get Recent Battles"):
100
+ tag_box = gr.Textbox(label="Player Tag", placeholder="#V2LQY9UY")
101
+ fetch_btn = gr.Button("Fetch")
102
+ json_out = gr.JSON(label="Battle Log")
103
+ fetch_btn.click(get_recent_battles, inputs=tag_box, outputs=json_out)
104
 
105
+ # ───────────────────────────────────────────────
106
+ # LAUNCH AS MCP SERVER
107
+ # ───────────────────────────────────────────────
108
+ if __name__ == "__main__":
109
+ demo.launch(mcp_server=True)