# mcp210x It's MCP. It's CP210x. It was right there the whole time. An MCP server for customizing Silicon Labs CP210x USB-UART bridge devices — product strings, serial numbers, power config, udev rules, and device locking — through natural language in Claude Code. Built on [FastMCP](https://gofastmcp.com/) with Python ctypes bindings to Silicon Labs' native `libcp210xmanufacturing` library. ## The problem You plug in three CP2102 boards. They all enumerate as: ``` Bus 001 Device 004: ID 10c4:ea60 Silicon Labs CP2102 USB to UART Bridge Controller Bus 001 Device 005: ID 10c4:ea60 Silicon Labs CP2102 USB to UART Bridge Controller Bus 001 Device 006: ID 10c4:ea60 Silicon Labs CP2102 USB to UART Bridge Controller ``` Which one is which? Unplug, replug, guess. `/dev/ttyUSB0` becomes `/dev/ttyUSB2` after a reboot. You write udev rules that match on nothing unique. The Silicon Labs GUI customization tool is 32-bit only and hasn't been updated since 2015. ## The fix ``` > What CP210x devices are connected? Two devices found: [0] RYLR998 0033001104645C0B00001130 (serial: 0001) [1] RYLR998 0033001104645C0B00000D27 (serial: 0001) > Set up a udev rule for device 0 so it always appears at /dev/rylr998-1130 ``` Each device gets a unique product string baked into its USB descriptor EPROM. Udev rules match on that string to create stable symlinks. Devices survive reboots, port reordering, and hub changes. ## Features - **List and inspect** connected CP210x devices (part number, VID/PID, strings, power, lock state) - **Write USB descriptors** — product string, manufacturer, serial number - **Configure power** — max current draw, self-powered vs bus-powered - **Generate udev rules** — stable `/dev/` symlinks based on product string - **Reset device** — trigger USB re-enumeration after changes - **Lock device** — permanently freeze configuration (with strict confirmation gate) ## Safety model CP210x descriptor EPROM is one-time-programmable with limited write cycles. Writes can't be undone. Locks are permanent. The server enforces a tiered confirmation model: | Operation | Confirmation | |-----------|-------------| | Reads | None | | Writes (strings, power) | MCP elicitation if client supports it; proceeds otherwise | | Lock | Elicitation **required**; hard-refuses without it | The lock gate isn't just a warning — it returns an error and does not proceed if the MCP client can't present a confirmation dialog. ## Requirements - Linux x86_64 - `libcp210xmanufacturing.so` — Silicon Labs CP210x manufacturing library - Python 3.10+ - [uv](https://docs.astral.sh/uv/) ## Installation ### 1. Native library **Arch Linux** (AUR package included): ```bash cd aur/cp210xmanufacturing makepkg -si ``` This installs the shared library, headers, and udev rules for non-root USB access. **From source:** ```bash cd AN721SW/Linux/LibrarySourcePackages/cp210xmanufacturing make LIB_ARCH=64 sudo make install sudo ldconfig ``` You'll also need udev rules for non-root device access — copy `aur/cp210xmanufacturing/SiliconLabs.rules` to `/usr/lib/udev/rules.d/` and reload. ### 2. MCP server ```bash uv tool install . ``` ### 3. Claude Code ```bash claude mcp add cp210x -- uvx mcp210x ``` For development (runs from source): ```bash claude mcp add cp210x-local -- uv run --directory /path/to/this-repo mcp210x ``` ## Tools | Tool | Description | |------|-------------| | `list_devices` | List connected CP210x devices with description and serial | | `get_device_info` | Full device details — part number, VID/PID, strings, power, lock state | | `set_product_string` | Write USB product string (max 126 chars) | | `set_manufacturer_string` | Write USB manufacturer string (max 45 chars) | | `set_serial_number` | Write USB serial number (max 63 chars) | | `set_max_power` | Set max USB power draw in mA (0-500, rounded to nearest 2) | | `set_self_powered` | Toggle self-powered vs bus-powered reporting | | `reset_device` | USB disconnect/reconnect to apply changes | | `lock_device` | Permanently freeze device configuration | | `setup_udev_rule` | Generate and install a udev rule for a stable `/dev/` symlink | ## Architecture ``` Claude Code ──stdio──▶ FastMCP server (server.py) │ ▼ Python ctypes (bindings.py) │ ▼ libcp210xmanufacturing.so │ ▼ libusb ──▶ CP210x device ``` The native library uses **libusb** for device access, separate from the kernel's `cp210x` serial driver. Both coexist — you can read/write UART data over `/dev/ttyUSB0` while customizing USB descriptors through this server. ## Project structure ``` mcp210x/ ├── src/mcp210x/ │ ├── server.py # FastMCP tool definitions and elicitation logic │ ├── bindings.py # ctypes wrapper for libcp210xmanufacturing.so │ └── __init__.py ├── aur/cp210xmanufacturing/ │ ├── PKGBUILD # Arch Linux package for the native library │ └── SiliconLabs.rules # udev rules for non-root USB access ├── AN721SW/ # Silicon Labs toolkit (library source) ├── docs/ # Datasheets and application notes └── pyproject.toml ``` ## Complementary tools This server handles **device customization** (USB descriptors, power config). For **serial communication** (sending/receiving data over UART), use [mcserial](https://git.supported.systems/MCP/mcserial). ## Reference - [CP2102 Datasheet](https://www.silabs.com/documents/public/data-sheets/CP2102-9.pdf) - [AN721: Device Customization Guide](https://www.silabs.com/documents/public/example-code/AN721SW.zip) — source for `libcp210xmanufacturing` - [AN197: Serial Communication Guide](https://www.silabs.com/documents/public/application-notes/an197-serial-communications-guide-cp210x.pdf) ## License MIT