Pongbot-MCP
An MCP server that lets Claude control a Pongbot Nova S Pro table tennis robot over Bluetooth LE. Describe a drill in plain language, moderate topspin to the forehand, alternating to the backhand every three balls, and Claude translates it into the robot's binary wire protocol and sends it directly, no tapping through the robot's own app. Working and actively developed, with an open bug documented in the README rather than hidden from it.
View repoArchitecture & Trade-offs
What was built, and what was deliberately chosen against.
Claude Desktop
│ MCP over stdio
▼
server.py MCP tools, natural-language-friendly descriptions
│
▼
presets.py named drill definitions
│
▼
protocol.py Ball / Drill dataclasses, byte packing
fully unit-tested, no hardware needed
│
▼
ble.py BleakClient: auth handshake, GATT writes,
notifications, keepalive
│ Bluetooth LE
▼
Pongbot Nova S Pro
Drill packing into the robot's binary format lives as plain dataclasses and byte packing, covered by a unit test suite that runs without a robot present. Only the Bluetooth layer, the connection lifecycle, the authentication handshake, GATT writes, notification subscriptions, has to be tested against a real device.
The robot speaks an undocumented Bluetooth LE protocol; the byte layouts, RPM formulas, parameter scaling, and the MD5 authentication handshake the robot demands before accepting any command all come from two other open-source projects, credited by name in the README. What this project adds is a Python reimplementation, an MCP server around it, and a Claude-shaped natural-language layer on top, not a rediscovery of the protocol itself.
The connection drops after roughly 13 minutes of idle time despite a keepalive packet sent every 10 seconds that is confirmably acknowledged by the robot. The keepalive is necessary but not sufficient, something else times out, and that's stated as an open, unsolved problem with its own reproduction script, not smoothed over as a minor caveat.
Stack
Python, Bluetooth LE (bleak), MCP SDK, uv
Status
Working, actively developed. Known open issue: idle disconnect after roughly 13 minutes (see Architecture & Trade-offs above). Personal project, no promises on issue or PR turnaround.
Public repo. View the repo on GitHub.
Back to work