Metadata-Version: 2.4
Name: wisent-wire-mcp
Version: 0.12.2
Summary: MCP server for the Wisent Wire hardware testing platform — drive power, GPIO, UART/RS485/CAN, firmware flashing, and GDB debug from an AI agent
Author-email: Wisent Wire <info@wisent-wire.com>
License-Expression: MIT
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: wisent-wire-sdk==0.12.2
Requires-Dist: mcp<2,>=1.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: responses>=0.23; extra == "dev"
Requires-Dist: ruff>=0.4; extra == "dev"
Dynamic: license-file

# wisent-wire-mcp

MCP (Model Context Protocol) server for the [Wisent Wire](https://wisent-wire.com) hardware testing platform. Lets AI assistants interact with WisentWire devices — power control, firmware flashing & flasher catalog, UART / RS485 / CAN buses, GPIO control & telemetry, GDB debug sessions, device registry, reservations, and protocol frame definitions.

## Installation

Requires Python **3.10+**. Install with [`pipx`](https://pipx.pypa.io) —
it puts the MCP server in an isolated environment and adds the
`wisent-wire-mcp` binary to your `PATH`.

### 1. Install `pipx` (one-time)

```bash
# macOS
brew install pipx
pipx ensurepath

# Linux / WSL
python3 -m pip install --user pipx
python3 -m pipx ensurepath
```

Open a new terminal so the updated `PATH` is picked up.

### 2. Install the MCP server

```bash
pipx install wisent-wire-mcp
```

Verify:

```bash
which wisent-wire-mcp         # ~/.local/bin/wisent-wire-mcp (or similar)
```

### 3. Upgrade / uninstall

```bash
pipx upgrade   wisent-wire-mcp
pipx uninstall wisent-wire-mcp
```

## Configuration

### `.mcp.json` location

Claude Code reads MCP servers from `.mcp.json`. Two scopes:

| Scope | Path | When to use |
|-------|------|-------------|
| **Project** | `<repo-root>/.mcp.json` | Shared with the project (checked into VCS or per-repo) |
| **User** | `~/.claude.json` under the `mcpServers` key | Available in every Claude Code session for this user |

Claude Desktop uses a separate file:

| Platform | Path |
|----------|------|
| macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |
| Windows | `%APPDATA%\Claude\claude_desktop_config.json` |
| Linux | `~/.config/Claude/claude_desktop_config.json` |

### Example `.mcp.json`

```json
{
  "mcpServers": {
    "wisent-wire": {
      "command": "wisent-wire-mcp",
      "env": {
        "WISENT_WIRE_API_KEY": "wwk_..."
      }
    }
  }
}
```

After editing `.mcp.json`, restart Claude Code (or reload the window)
for the server to be picked up.

### Environment variables

| Variable | Required | Description |
|----------|----------|-------------|
| `WISENT_WIRE_API_KEY` | Yes* | API key (`wwk_…`). **Recommended** — create one under **Settings → API keys**. |
| `WISENT_WIRE_EMAIL` | Yes* | Account email. |
| `WISENT_WIRE_PASSWORD` | Yes* | Account password. |
| `WISENT_WIRE_URL` | No | API base URL. Omit it to target production. |

\* Provide either `API_KEY` or `EMAIL` + `PASSWORD`. The API key is tried first.

`WISENTWIRE_API_KEY` (no underscore) still works as a **deprecated** alias and
warns on use — it is the one legacy spelling with released history. The same
names configure the `wisent-wire-sdk` package, so one exported environment does
both. An exported-but-empty value counts as unset.

The server reads none of these itself — it hands the whole job to the SDK, which
is what keeps the two from disagreeing about a name. See the SDK README for the
canonical list.

**Choosing a backend.** `WISENT_WIRE_URL` is the address, and omitting it targets
production (`https://app.wisent-wire.com`). To point at integration, or at a
backend running on your own machine:

```json
"env": {
  "WISENT_WIRE_URL": "https://int.wisent-wire.com",
  "WISENT_WIRE_API_KEY": "wwk_..."
}
```

There is no named-environment form. `WISENT_WIRE_ENV` used to exist and was what
this page recommended; setting it now **stops the server with an error naming
the replacement**, rather than being ignored and quietly starting against
production. If you configured this server during a release candidate, that is
the line to change.

For a local backend, use its address — `"WISENT_WIRE_URL": "http://localhost:7998"`.
Mint a key for it once with the header the local gateway trusts:

```bash
curl -sS -X POST http://localhost:7998/api/me/api-keys \
  -H 'X-Forwarded-User-Email: e2e@wisentwire.test' \
  -H 'Content-Type: application/json' -d '{"name":"local"}'
```

### Available tools

57 tools, grouped below.

#### System & Device

| Tool | Description |
|------|-------------|
| `get_backend_version` | Get the backend version |
| `list_wisentwires` | List all WisentWire devices |
| `get_ww_status` | Get current device status |
| `check_ww_available` | Check if a device is available |
| `rename_wisentwire` | Change a device display name — that field only, nothing else |

#### Device Registry

| Tool | Description |
|------|-------------|
| `list_registered_devices` | List registered devices, optionally filtered by label |
| `list_connected_devices` | Scan a WisentWire and list physically connected devices |
| `register_device` | Register a device against a fingerprint |

#### Power & Telemetry

| Tool | Description |
|------|-------------|
| `power_on` / `power_off` | Control power supply |
| `update_power_supply` | Change voltage / current limit while powered |
| `get_telemetry` | Recent voltage/current readings |
| `set_power_supply_telemetry` | Enable or disable power telemetry streaming |

#### GPIO

| Tool | Description |
|------|-------------|
| `get_gpio_shadow` | Current GPIO pin states |
| `get_gpio_names` | Pin name mapping for a device |
| `set_gpio_output` | Drive an output pin high or low |
| `set_gpio_input_pull_policy` | Set an input pin's pull policy |
| `set_gpio_telemetry` | Enable or disable GPIO telemetry streaming |
| `get_gpio_telemetry` | Recent GPIO telemetry readings |

#### Firmware & Flashing

| Tool | Description |
|------|-------------|
| `list_firmware` | List firmware binaries with their tag ids |
| `list_firmware_tags` | List the org firmware tags with the ids `set_firmware_tags` takes |
| `create_firmware_tag` | Create an org-wide firmware tag |
| `set_firmware_tags` | Replace **all** tags on a binary — not additive |
| `get_firmware_download_url` | Short-lived pre-signed download link for a binary |
| `upload_firmware` | Upload a firmware binary |
| `delete_firmware` | Delete a firmware binary |
| `flash_firmware` | Flash firmware to a device (msp430/openocd/st-link/j-link). `device_id` picks which probe, when more than one is attached |
| `flash_firmware_file` | One-shot: upload a local firmware file, flash it, then delete it (by default). Also takes `device_id` |
| `list_launch_commands` | Valid target/programmer/interface/toolchain combinations. Needs at least one filter — unfiltered the catalog is too large for the backend to return |
| `list_programmers` | Probe types (ST-Link v3, J-Link, ...) with the ids `register_device` needs |
| `list_targets` | Find flashable chips by name fragment and get the `target_id` `list_launch_commands` needs |
| `get_flash_status` | Check a flash job's status by job id |
| `get_flasher_logs` | Get flasher debug logs |

#### Debug

| Tool | Description |
|------|-------------|
| `get_debug_state` | Get the current GDB debug session state |
| `get_debug_job_status` | Get a debug job's status by id |
| `get_debug_logs` | Buffered device-side debug log; the `last_n` most recent entries (default 50) |
| `stop_debug` | Stop the active debug session |

#### UART & Buses

| Tool | Description |
|------|-------------|
| `send_uart_command` | Send a text command over UART |
| `send_uart_hex` | Send raw hex bytes over UART |
| `send_rs485_hex` | Send raw hex bytes over RS485 |
| `send_can_frame` | Send a CAN frame |
| `get_uart_log` | Get TX/RX message history |
| `get_bus_log` | Get TX/RX message history for a given bus (uart/rs485/can) |

#### Frame Definitions

| Tool | Description |
|------|-------------|
| `list_frame_definitions` | List all frame definitions |
| `get_frame_definition` | Get a frame definition with fields |
| `create_frame_definition` | Create a new frame definition |
| `update_frame_definition` | Update a frame definition |
| `delete_frame_definition` | Delete a frame definition |

#### Commands

| Tool | Description |
|------|-------------|
| `list_commands` | List commands for a frame definition |
| `get_command` | Get one command with the field values bound to it |
| `create_command` | Create a command |
| `update_command` | Update a command |
| `delete_command` | Delete a command |

#### Reservations

| Tool | Description |
|------|-------------|
| `list_reservations` | List reservations |
| `get_reservation` | Get a single reservation |
| `create_reservation` | Create a reservation |
| `delete_reservation` | Delete a reservation |


## Development

```bash
pip install -e ".[dev]"
pytest tests/ -v
ruff check src/ tests/
```

## License

MIT
