Files
flipper-bridge/flipper-universal/flipper-universal-mcp.py

159 lines
4.0 KiB
Python

from fastmcp import FastMCP
import serial
import time
import os
mcp = FastMCP("Flipper Zero - Universal CLI")
FLIPPER_PORT = os.getenv("FLIPPER_PORT", "/dev/cu.usbmodemflip_Il1chih41")
def send_flipper_cmd(cmd: str) -> str:
"""Send ANY Flipper CLI command and return output"""
try:
with serial.Serial(FLIPPER_PORT, 115200, timeout=3) as ser:
time.sleep(0.5) # let port settle
ser.reset_input_buffer()
# Send command
ser.write((cmd + "\r\n").encode())
time.sleep(0.8)
# Read response
output = ""
while ser.in_waiting:
output += ser.read(ser.in_waiting).decode(errors="ignore")
time.sleep(0.1)
# Strip the command echo and prompt
lines = [l for l in output.splitlines()
if l.strip() and not l.strip().endswith(">:") and cmd not in l]
return "\n".join(lines) or f"Executed: {cmd}"
except Exception as e:
return f"Error: {str(e)}"
@mcp.tool()
def flipper(cmd: str):
"""Send ANY Flipper CLI command. Examples:
- 'ir universal LG_Hotel_tv Power'
- 'nfc scene read'
- 'subghz tx 433.92M test.sub'
- 'device_info'
- 'gpio pins'"""
return send_flipper_cmd(cmd)
@mcp.tool()
def flipper_ir(remote: str, signal: str):
"""IR shortcut: flipper_ir('LG_Hotel_tv', 'Power')"""
return send_flipper_cmd(f"ir universal {remote} {signal}")
@mcp.tool()
def flipper_list_commands():
"""List all available Flipper commands"""
return send_flipper_cmd("help")
# STORAGE
@mcp.tool()
def flipper_ls(path: str = "/ext"):
"""List files: flipper_ls('/ext')"""
return send_flipper_cmd(f"storage list {path}")
@mcp.tool()
def flipper_cat(file: str):
"""Read file: flipper_cat('/ext/test.txt')"""
return send_flipper_cmd(f"storage read {file}")
@mcp.tool()
def flipper_mkdir(folder: str):
"""Create folder: flipper_mkdir('/ext/my_folder')"""
return send_flipper_cmd(f"storage mkdir {folder}")
@mcp.tool()
def flipper_rm(file: str):
"""Delete: flipper_rm('/ext/unwanted.txt')"""
return send_flipper_cmd(f"storage remove {file}")
# APPS
@mcp.tool()
def flipper_apps_list():
"""List all Flipper apps"""
return send_flipper_cmd("loader list")
@mcp.tool()
def flipper_app_open(app: str):
"""Open app: flipper_app_open('ir')"""
return send_flipper_cmd(f"loader open {app}")
@mcp.tool()
def flipper_app_close():
"""Close current app"""
return send_flipper_cmd("loader close")
# APPS (loader)
@mcp.tool()
def flipper_ir():
"""Launch Infrared"""
return send_flipper_cmd("loader open ir")
@mcp.tool()
def flipper_nfc():
"""Launch NFC"""
return send_flipper_cmd("loader open nfc")
@mcp.tool()
def flipper_subghz():
"""Launch Sub-GHz"""
return send_flipper_cmd("loader open subghz")
@mcp.tool()
def flipper_rfid():
"""Launch 125kHz RFID"""
return send_flipper_cmd("loader open rfid")
@mcp.tool()
def flipper_rfid_13():
"""Launch 13.56MHz RFID"""
return send_flipper_cmd("loader open rfid_13")
@mcp.tool()
def flipper_gpio():
"""Launch GPIO"""
return send_flipper_cmd("loader open gpio")
@mcp.tool()
def flipper_bt():
"""Launch Bluetooth"""
return send_flipper_cmd("loader open bt")
@mcp.tool()
def flipper_clock():
"""Launch Clock"""
return send_flipper_cmd("loader open Clock")
@mcp.tool()
def flipper_archive():
"""Launch File Archive"""
return send_flipper_cmd("loader open Archive")
@mcp.tool()
def flipper_settings():
"""Launch Settings"""
return send_flipper_cmd("loader open Settings")
@mcp.tool()
def flipper_badusb():
"""Launch BadUSB"""
return send_flipper_cmd("loader open BadUSB")
@mcp.tool()
def flipper_i2c():
"""Launch I2C"""
return send_flipper_cmd("loader open i2c")
@mcp.tool()
def flipper_onewire():
"""Launch 1-Wire"""
return send_flipper_cmd("loader open onewire")
if __name__ == "__main__":
mcp.run(transport="stdio")