MCP server by aeo24
FOME ECU MCP Server
An MCP (Model Context Protocol) server that lets Claude Code tune a FOME ECU directly over USB serial — no TunerStudio required. Includes a simulator mode that replays data from MLG log files for development without hardware.
The Car
- 1999 Mazda Miata (NB1), turbocharged
- ECU: Beer Money Motorsports PNP NB1 board running FOME firmware
- Firmware:
rusEFI (FOME) .2025.11.03.hellen-nb1.2444532447
Architecture
Claude Code <--stdio/MCP--> FastMCP Server (Python) <--pyserial--> FOME ECU
|
SimulatorBackend (dev mode, replays MLG data)
53 MCP Tools
Connection & Real-Time Data
| Tool | Description |
|------|-------------|
| connect_ecu | Connect to real ECU or simulator |
| disconnect_ecu | Disconnect from ECU |
| get_connection_status | Check connection state |
| read_realtime_snapshot | Single snapshot of all engine data |
| read_realtime_stream | Stream engine data for up to 30 seconds |
16x16 Tuning Tables (VE, Ignition, Lambda)
| Tool | Description |
|------|-------------|
| read_ve_table | Read volumetric efficiency table |
| write_ve_cells | Write VE cells with bounds checking and verification |
| read_ignition_table | Read ignition timing advance table |
| write_ignition_cells | Write timing cells with verification |
| read_lambda_table | Read lambda/AFR target table |
| write_lambda_cells | Write lambda cells with verification |
Idle Control
| Tool | Description |
|------|-------------|
| read_idle_config | Read full idle PID config |
| write_idle_pid_gains | Set P/I/D gains for idle RPM control |
| write_idle_pid_limits | Set PID output and iTerm limits |
| write_idle_timing_pid_gains | Set idle timing advance PID |
| read_idle_target_curve | Read CLT -> target RPM curve (16-point) |
| write_idle_target_curve | Write target RPM vs coolant temp |
| read_idle_corr_curve | Read CLT -> idle position correction |
| write_idle_corr_curve | Write idle position correction curve |
Engine Configuration
| Tool | Description |
|------|-------------|
| read_rev_limiter | Read hard RPM limit and launch control RPM |
| write_rev_limiter | Set RPM limiters |
| read_cranking_config | Read cranking timing, fuel mass, timing mode |
| write_cranking_timing | Set cranking and fixed timing angles |
| write_global_fuel_correction | Set global fuel multiplier |
| read_cranking_fuel_curve | Read CLT -> cranking fuel coefficient (8-point) |
| write_cranking_fuel_curve | Write cranking fuel vs coolant temp |
| read_post_crank_config | Read post-start enrichment (8x8 table + scalars) |
| write_post_crank_scalars | Set post-crank factor and duration |
| write_post_crank_cells | Write post-crank enrichment table cells |
| read_accel_enrich_config | Read TPS acceleration enrichment (8x8 table) |
| write_accel_enrich_scalars | Set accel enrichment threshold and lookback |
| write_accel_enrich_cells | Write accel enrichment table cells |
| read_fan_config | Read cooling fan on/off temperatures |
| write_fan_config | Set fan temperature thresholds |
| read_boost_cut | Read overboost protection pressure |
| write_boost_cut | Set boost cut pressure threshold |
| read_injector_config | Read injector flow rate and dead time curve |
| write_injector_flow | Set injector flow rate (cc/min) |
| write_injector_dead_time | Write injector dead time vs battery voltage |
Closed-Loop Fuel (STFT)
| Tool | Description |
|------|-------------|
| read_stft_config | Read full closed-loop fuel config |
| write_stft_enable | Enable/disable closed-loop fuel correction |
| write_stft_config | Set STFT startup delay, min CLT, deadband |
| write_stft_region | Configure per-region trim limits (idle/overrun/power/main) |
Flash & Change Tracking
| Tool | Description |
|------|-------------|
| burn_to_flash | Persist RAM changes to flash |
| get_pending_changes | List unburned RAM changes |
| get_change_history | View timestamped change audit trail |
Log Analysis
| Tool | Description |
|------|-------------|
| load_mlg_log | Load and summarize an MLG log file |
| analyze_log_channel | Get statistics for a log channel |
| analyze_afr_deviation | Analyze AFR vs target across RPM/MAP bins |
| suggest_ve_corrections | Calculate VE table corrections from log data |
Simulator Control
| Tool | Description |
|------|-------------|
| simulator_load_log | Load MLG file for playback |
| simulator_set_position | Seek to a specific log record |
| simulator_get_status | Get playback position and status |
Safety
- All writes go to RAM only — burn to flash is always a separate explicit action
- Bounds checking on every write: VE 0-255%, timing -20 to 90 deg, lambda 0.6-1.5
- Validate-before-write: batch changes are fully validated before any writes occur
- Read-back verification on all table writes (VE, ignition, lambda)
- Row/col bounds checking prevents writes outside table boundaries
- All changes logged to
changes.jsonlwith timestamps
Setup
# Clone
git clone https://github.com/aeo24/FOME_MCP.git
cd FOME_MCP
# Install
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
# Run tests
pytest tests/ -v # 55 tests
MCP Server Configuration
Add to your Claude Code MCP config (.mcp.json):
{
"mcpServers": {
"fome_ecu": {
"type": "stdio",
"command": "/path/to/FOME_MCP/.venv/bin/python3",
"args": ["-m", "fome_mcp.server"],
"env": {
"PYTHONPATH": "/path/to/FOME_MCP/src",
"FOME_MODE": "simulator",
"FOME_MLG_PATH": "/path/to/your/log.mlg"
}
}
}
}
Set FOME_MODE=real and optionally FOME_PORT=/dev/cu.usbmodemXXXX for hardware.
Protocol
- Baud: 115200, 8N1
- Envelope: msEnvelope_1.0 (big-endian framing, little-endian data)
- Commands: S (query), R (read page), C (write chunk), B (burn), O (output channels)
- Config page: 22,616 bytes, single page
- Output channels: 1,288 bytes
- Blocking factor: 1,300 bytes max per read/write
Project Structure
src/fome_mcp/
server.py # FastMCP entry point, 53 MCP tools
protocol/
constants.py # All offsets verified against INI
framing.py # msEnvelope_1.0 packet framing + CRC32
commands.py # High-level command wrappers
serial_conn.py # Serial port communication
ecu/
backend.py # Abstract backend interface
simulator.py # Simulator using MLG + embedded MSQ
real_ecu.py # Real hardware backend
tables.py # 16x16 table read/write (VE, ignition, lambda)
idle.py # Idle PID configuration
engine_config.py # Engine config (rev limit, cranking, accel enrich, etc.)
output_channels.py # Real-time data decoding
safety/
bounds.py # Value bounds checking
verification.py # Write read-back verification
change_log.py # Timestamped change audit trail
analysis/
mlg_parser.py # MLVLG v2 binary log parser
msq_parser.py # TunerStudio MSQ XML parser
tests/ # 55 tests
fome_hellen-nb1.ini # FOME INI (ground truth for offsets)
License
MIT