mcp-brawlstats / app.py
HongyiShi's picture
allow user input to decide API key in-session
5bfb623
"""
MCP-ready Gradio app
β€’ Tool 1: save_brawlstars_key(api_key) β†’ str
β€’ Tool 2: get_recent_battles(player_tag) β†’ dict
UI: two tabs so humans can still use the app.
"""
import gradio as gr
import brawlstats # pip install brawlstats
# ───────────────────────────────────────────────
# GLOBAL STATE (shared by all tool invocations)
# ───────────────────────────────────────────────
BS_API_KEY = None # will hold the token after Tool-1 runs
# ───────────────────────────────────────────────
# TOOL 1 – save the key (no echo)
# ───────────────────────────────────────────────
def save_brawlstars_key(api_key: str) -> str:
"""
Store a Brawl Stars API key in server memory for later use.
This should be the **first** tool called in a session. Once the key
is saved, subsequent calls to `get_recent_battles` can access the API
without requiring the LLM (or user) to resend the long token.
Args:
api_key (str): Your personal token generated at
https://developer.brawlstars.com. Do **not** share this
publiclyβ€”send it only once via this tool.
Returns:
str: Status message β€”
β€’ "βœ… API key saved in server memory" on success
β€’ "❌ No key provided" if the argument was empty
"""
global BS_API_KEY
BS_API_KEY = api_key.strip()
if BS_API_KEY:
return "βœ… API key saved in server memory"
return "❌ No key provided"
# ───────────────────────────────────────────────
# TOOL 2 – fetch recent battles using saved key
# ───────────────────────────────────────────────
def get_recent_battles(player_tag: str) -> dict:
"""
Retrieve a player's 25 most-recent Brawl Stars battles.
Call `save_brawlstars_key` **once** beforehand to cache the API key.
Args:
player_tag (str): The player’s in-game tag, with or without the
leading '#', e.g. "#V2LQY9UY" or "V2LQY9UY".
Returns:
dict: On success –
{
"player": "#TAG",
"count": <int>, # number of battles returned
"battles": <list[dict]> # raw JSON from Supercell
}
On failure –
{ "error": "<human-readable message>" }
"""
if not BS_API_KEY:
return {"error": "API key not set - call save_brawlstars_key first"}
tag = player_tag.strip().upper().lstrip("#")
try:
client = brawlstats.Client(BS_API_KEY)
logs = client.get_battle_logs(tag) # BattleLog object
except brawlstats.Forbidden:
return {"error": "Invalid API key"}
except brawlstats.NotFound:
return {"error": f"Player #{tag} not found"}
except brawlstats.RequestError as e:
return {"error": f"API request failed: {e}"}
return {
"player": f"#{tag}",
"count": len(logs),
"battles": logs.raw_data # serialisable list
}
# ───────────────────────────────────────────────
# HUMAN-FRIENDLY UI (optional)
# ───────────────────────────────────────────────
with gr.Blocks(title="Brawl Stars MCP Tools") as demo:
with gr.Tab("πŸ”‘ Save API Key"):
api_box = gr.Textbox(type="password", label="API Key")
save_btn = gr.Button("Save")
save_out = gr.Textbox(label="Status", interactive=False)
save_btn.click(save_brawlstars_key, inputs=api_box, outputs=save_out)
with gr.Tab("πŸ“œ Get Recent Battles"):
tag_box = gr.Textbox(label="Player Tag", placeholder="#V2LQY9UY")
fetch_btn = gr.Button("Fetch")
json_out = gr.JSON(label="Battle Log")
fetch_btn.click(get_recent_battles, inputs=tag_box, outputs=json_out)
# ───────────────────────────────────────────────
# LAUNCH AS MCP SERVER
# ───────────────────────────────────────────────
if __name__ == "__main__":
demo.launch(mcp_server=True)