STM32-MCP
Acesse o STM32CubeIDE e as ferramentas de depuração
Documentação
stm32-mcp
Servidor MCP que permite ao Claude Code compilar, gravar e se comunicar com hardware STM32.
O stm32-mcp é bem específico para a forma como costumo abordar desenvolvimento de hardware, mas provavelmente é útil para outras pessoas também! Ele pode ser adaptado para muitos fluxos de trabalho, mas é focado no meu (stlink-v3 mini, VCP nesse conector, microcontrolador STM32).
Você pode fazer coisas como:
eu: ei, quem está conectado agora?
claude: duas sondas sem nome conectadas a duas PCBs sem nome
eu: ok, pergunte quem são e dê um apelido com base na resposta delas
claude: entendido, você quer apelidar as sondas também? suas placas são 'campainha A' e 'sintetizador B'
eu: sim, coloquei marcador de tinta nessas sondas. chame a da campainha de 'azul' e a do sintetizador de 'vermelho'
claude: pronto. o que vem a seguir?
eu: dê comandos VCP para ambas para que possam conversar entre si, depois faça a campainha convidar o sintetizador para um encontro
claude: pensando... pronto, o sintetizador recusou. há muitos peixes no mar, campainha!
MCP (Model Context Protocol) é um padrão aberto que permite que assistentes de IA como o Claude usem ferramentas externas. Este servidor dá ao Claude a capacidade de compilar seu firmware, gravá-lo em uma placa, conversar com ele via serial e ler memória via SWD. É flexível e conversacional.
[!WARNING] Este servidor dá a uma IA acesso direto ao seu compilador, sonda de depuração e portas seriais. Ele pode gravar firmware, sobrescrever memória e enviar dados arbitrários ao seu hardware. Isso é poderoso e útil, mas não é uma sandbox. Saiba o que está conectado antes de deixá-lo agir.
Pré-requisitos
- STM32CubeIDE instalado em
/Applications/STM32CubeIDE.app(macOS) ou/opt/st/stm32cubeide_*(Linux) - Python 3.10+
- OpenOCD (
brew install open-ocd) — para gravação, leitura/escrita de memória e monitoramento ao vivo - ferramentas stlink de código aberto (
brew install stlink) — para enumeração de sondas - ST-Link conectado via USB (para informações de gravação/placa)
- Porta serial disponível (ST-Link VCP ou adaptador USB-UART)
Instalação
git clone https://github.com/shieldyguy/stm32-mcp.git
cd stm32-mcp
python3 -m venv .venv
source .venv/bin/activate
pip install -e .
Registrar com o Claude Code
Opção A: CLI
claude mcp add stm32 -- /path/to/stm32-mcp/.venv/bin/python -m stm32_mcp.server
Opção B: Configuração do projeto
Adicione ao .claude/settings.json ou .claude.json do seu projeto:
{
"mcpServers": {
"stm32": {
"command": "/path/to/stm32-mcp/.venv/bin/python",
"args": ["-m", "stm32_mcp.server"]
}
}
}
CLI autônoma
bin/ contém quatro wrappers finos sobre o mesmo código que as ferramentas MCP usam
| Comando | Uso |
|---|---|
stm32-list | Lista sondas + placas conectadas com apelidos |
stm32-flash | stm32-flash <probe|board> <file.elf> [--noverify] [--noreset] |
stm32-build | stm32-build <project_path> [Debug|Release] [--clean] |
stm32-bf | stm32-bf <project_path> <probe|board> [Debug|Release] [--clean] |
stm32-help | Lista esses comandos com seus usos (gerado automaticamente a partir dos scripts) |
Adicione bin/ ao seu PATH:
export PATH="/path/to/stm32-mcp/bin:$PATH"
Apelidos de sondas e apelidos de placas são resolvidos.
As compilações compartilham o bloqueio do workspace headless do CubeIDE do MCP, então um
stm32-build/stm32-bf competindo com uma compilação orientada por agente ficará na fila atrás dela.
Ferramentas Disponíveis
Compilação e Gravação
| Ferramenta | Descrição |
|---|---|
stm32_build | Compila firmware usando o builder headless do CubeIDE |
stm32_flash | Grava .elf/.bin/.hex na placa via ST-Link SWD |
stm32_build_and_flash | Compila + grava em um único passo (o caso de 90%) |
stm32_board_info | Lê informações do ST-Link/MCU (ID do dispositivo, tamanho da flash, tensão) |
Gerenciamento Multi-Placa
| Ferramenta | Descrição |
|---|---|
stm32_list_probes | Mostra todas as placas conectadas com apelidos e IDs de MCU |
stm32_set_nickname | Nomeia uma placa (por UID do MCU) ou sonda (por SN do ST-Link) |
Apelidos de placas seguem o MCU físico (persistem entre trocas de sonda). Apelidos de sondas seguem o hardware ST-Link. Use apelidos em qualquer parâmetro probe em todas as ferramentas.
Comunicação Serial
| Ferramenta | Descrição |
|---|---|
serial_list_ports | Lista portas seriais (marca portas ST-Link VCP com apelidos) |
serial_connect | Abre uma conexão serial |
serial_send | Envia dados e lê a resposta |
serial_read | Lê dados seriais em buffer |
serial_disconnect | Fecha uma conexão serial |
serial_sequence | Executa sequências multi-etapa de envio/atraso/memória em uma única chamada |
Depuração e Monitoramento
| Ferramenta | Descrição |
|---|---|
stm32_read_memory | Lê memória por endereço ou nome de variável (dos símbolos ELF) |
stm32_write_memory | Escreve memória por endereço ou nome de variável |
live_memory_start | Inicia monitoramento contínuo de memória em segundo plano via SWD |
live_memory_read | Lê entradas recentes de uma sessão de memória ao vivo |
live_memory_stop | Para uma sessão de memória ao vivo |
Sequências de Hardware
serial_sequence agenda múltiplas etapas (envio serial, atraso, captura de webcam e leitura/escrita de memória SWD) em uma única chamada de ferramenta. Atrasos usam um time.sleep() no thread do executor. O Claude não consegue cronometrar chamadas de ferramenta individuais de forma confiável, então isso permite temporização precisa de comandos e expectativas.
Tipos de etapa
[
{ "send": "SIM_LEFT", "to": "/dev/cu.usbmodem11202" },
{ "delay_ms": 500 },
{
"send": "GET_BLINK_STATE",
"to": "/dev/cu.usbmodem11402",
"expect": "BLINK"
},
{ "capture": true, "label": "post_brake" },
{
"mem_write": true,
"address": "0x48000418",
"value": "0x40",
"probe": "yellow"
},
{ "delay_ms": 1000 },
{
"mem_read": true,
"address": "0x48000400",
"count": 2,
"probe": "yellow",
"label": "gpio_post"
}
]
- Etapa de envio:
{send, to, expect?, read_timeout?, line_ending?}—toé o caminho da porta deserial_connect - Etapa de atraso:
{delay_ms}—time.sleep()real, não idas e voltas de chamadas de ferramenta - Etapa de captura:
{capture: true, label?, device_index?}— PNG salvo em/tmp/stm32-captures/ - Etapa de escrita de memória:
{mem_write: true, address | symbol + elf_path, value, probe, width?} - Etapa de leitura de memória:
{mem_read: true, address | symbol + elf_path, probe, count?, width?, label?}
Notas sobre etapas de memória:
probeaceita SN do ST-Link, apelido de sonda ou apelido de placaaddressé hexadecimal (ex.:"0x48000418"); alternativamente, usesymbol+elf_pathpara resolver por nomewidthé 8/16/32 bits, padrão 32 (detectado automaticamente a partir do tamanho do símbolo ao usarsymbol)- Cada operação de memória atualmente inicia um novo processo OpenOCD (~dezenas de ms de overhead por operação), então a temporização entre operações de memória abaixo de ~50ms é aproximada. Os atrasos em si são precisos.
Parâmetros
on_failure:"continue"(padrão) executa todas as etapas independentemente."stop"aborta na primeira falha.filter_responses: Quandotrue, padrõesexpectcorrespondem apenas a linhas de resposta VCP prefixadas com>(ignora ruído de depuração).
Saída
Step 1 [/dev/cu.usbmodem11202] SEND: SIM_LEFT
Response: >OK:SIM_LEFT
Step 2 DELAY: 500ms
Step 3 [/dev/cu.usbmodem11402] SEND: GET_BLINK_STATE
Response: >BLINK_STATE:BLINK
Expect "BLINK": PASS
Step 4 [yellow] MEM_WRITE: Wrote 0x00000040 to 0x48000418
Step 5 DELAY: 1000ms
Step 6 [yellow] MEM_READ: gpio_post 0x48000400: 0xabffdfff 0x00000080
Summary: 2/2 sends OK, 1/1 assertions PASS, 1/1 mem_writes OK, 1/1 mem_reads OK
Monitoramento de Memória ao Vivo
Monitore variáveis de firmware em tempo real via SWD, sem modificar o firmware ou usar serial. O OpenOCD roda como um subprocesso persistente e consulta variáveis através de seu socket TCL integrado.
Iniciar uma sessão
live_memory_start(
variables='["blink", "ts"]', # symbol names from ELF
elf_path="/path/to/firmware.elf",
probe="taillight", # board/probe nickname
interval_ms=500 # min 250ms
)
As variáveis podem ser:
- Nomes de símbolos (strings):
"blink"— resolvidos do ELF viaarm-none-eabi-nm - Dicionários com símbolo + tipo:
{"symbol": "temperature", "type": "float"}— interpreta valor de 32 bits como IEEE 754 - Dicionários com endereço bruto:
{"address": "0x20000304", "name": "x", "width": 32}
Ler valores recentes
live_memory_read(session_id="abc123", last_n=10)
Retorna entradas recentes de um buffer circular em memória (máximo de 100 entradas). O histórico completo é gravado no arquivo de saída JSONL.
Formato de saída JSONL
{ "t": 1709830123.456, "elapsed_s": 1.002, "values": { "blink": 65539 } }
Parar uma sessão
live_memory_stop(session_id="abc123")
Retorna estatísticas: duração, contagem de leituras, contagem de erros, caminho do arquivo de saída.
Restrições
- Uma sessão por sonda — esta é uma restrição de hardware (conexão SWD única)
- Pare antes de gravar —
live_memorymantém a conexão SWD;stm32_flashestm32_read/write_memoryfalharão se uma sessão estiver ativa - Porta TCL 6666 — padrão do OpenOCD. Pare outras instâncias do OpenOCD primeiro se houver conflito
Padrões Seriais
- Taxa de baud: 115200
- Fim de linha: LF (
\n) - Polling de leitura: 50ms de pausa entre bytes, 200ms de pausa por silêncio
- Limites de buffer: máximo de 4096 bytes por leitura
Desenvolvimento
MCP Inspector
source .venv/bin/activate
mcp dev src/stm32_mcp/server.py
Teste de Loopback
As ferramentas seriais podem ser testadas sem hardware usando o loopback do pyserial:
import serial
ser = serial.serial_for_url("loop://", baudrate=115200, timeout=0.1)
ser.write(b"PING\n")
print(ser.read(100)) # b'PING\n'