# MCP Settings Persistence Bug — SD vs Internal (2026-07-13) ## Symptom User enables MCP Screen in Settings → go back → shows disabled again. `/api/mcp` returns `404: MCP server is disabled`. Board: ES3C28P (color 2.8" ILI9341V, 16MB + PSRAM, `storage.userDataLocation=SD`). ## Root Cause `Tactility/Source/settings/McpSettings.cpp` hardcoded: ```cpp constexpr SETTINGS_FILE = "/data/service/mcp/settings.properties"; file::findOrCreateDirectory("/data/service/mcp", 0755); ``` - On SD boards, `getUserDataPath()` = `/sdcard/tactility` (see `Paths.cpp:getUserDataRootPath()` → finds SDCARD_TYPE FS) - Internal `/data` partition may not be mounted, is read-only, or gets wiped on SD mode - `save()` wrote to internal, `load()` on next boot looked at internal but file missing → return false → default `mcpEnabled=false` Other settings (`WebServerSettings`, `DisplaySettings`, `DevelopmentSettings`) correctly used `getUserDataPath() + "/settings/..."`. ## Fix Applied 2026-07-13 ```cpp #include static std::string getSettingsFilePath() { return getUserDataPath() + "/settings/mcp.properties"; } bool load(...) { auto p = getSettingsFilePath(); if (!file::isFile(p)) return false; return file::loadPropertiesFile(p, map); } bool save(...) { auto p = getSettingsFilePath(); if (!file::findOrCreateParentDirectory(p, 0755)) return false; return file::savePropertiesFile(p, map); } McpSettings loadOrGetDefault() { McpSettings s; if (!load(s)) { s=getDefault(); save(s); } return s; } ``` ## Pitfall Checklist for New Settings - [ ] Never hardcode `/data/...` - [ ] Use `getUserDataPath()` + "/settings/.properties" - [ ] Include `Tactility/Paths.h` - [ ] Guard load with `isFile(path)` before parse (matches WebServerSettings) - [ ] Use `findOrCreateParentDirectory` not `findOrCreateDirectory` on file path - [ ] `loadOrGetDefault()` saves default if missing ## Verification - Ad-hoc script `hermes-verify-*.py` checks old path removed + new path present + parent dir creation - Live probe: after enabling MCP on device, POST `/api/mcp {method:tools/list}` returns tool list, not 404 - SD path physically: `/sdcard/tactility/settings/mcp.properties` should contain `mcpEnabled=true` ## Related Bugs Same Session - HttpServer ctrl_port collision (8080+6666 both 32768) → `config.ctrl_port = 32768 + (port % 1000)` - DisplayIdle early return on `!supportsBacklightDuty()` → killed timer, broke MCP manual activation on RLCD - `CONFIG_HTTPD_MAX_URI_HANDLERS=8` < 9 needed → bump to 20 - Video stream task stack 4096 → 8192 + idle delay 50ms See `webserver-devserver.md` for full coexistence debugging.