159 lines
4.0 KiB
Python
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") |