stm32-stlink-mcp
Provides tools for debugging and flashing STM32 microcontrollers via ST-LINK probes, including session management, breakpoints, memory/register access, expression evaluation, and standalone flashing.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@stm32-stlink-mcp connect to STM32 and set a breakpoint at main"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
stm32-stlink-mcp
MCP server for debugging STM32 microcontrollers over ST-LINK, built on STMicroelectronics' own
STM32CubeCLT toolset — ST-LINK_gdbserver, STM32_Programmer_CLI, and arm-none-eabi-gdb
(driven via GDB/MI2). No OpenOCD, J-Link, or probe-rs involved.
Architecture
A debug session is a pair of child processes, exactly mirroring ST's own documented workflow (UM2576, "STM32CubeIDE ST-LINK GDB server"):
arm-none-eabi-gdb --interpreter=mi2 --(TCP, target extended-remote)--> ST-LINK_gdbserver --(USB)--> ST-LINK --(SWD)--> STM32arm-none-eabi-gdb is driven in MI2 mode so the server gets source-level stepping, symbolic
breakpoints, and symbol-aware expression evaluation for free, instead of hand-rolling the GDB
Remote Serial Protocol. ST-LINK_gdbserver owns the USB handle to the probe for the lifetime of
the session; flashing via gdb's load (MI: -target-download) is transparently delegated by the
server to STM32CubeProgrammer, so no session teardown is needed to reflash. A standalone
one-shot flash (flash_standalone, no session required) invokes STM32_Programmer_CLI directly
and therefore conflicts with an already-open session on the same probe — see the tool description.
Related MCP server: dbgprobe-mcp-server
Setup
npm install
npm run buildRequires STM32CubeCLT to be installed and its bin/ directories reachable — either already on
PATH (the CLT installer does this by default) or via STMCP_CUBECLT_PATH / per-tool overrides.
Run npm run doctor to check.
Running
node dist/index.js serve # starts the MCP server on stdio (default mode)
node dist/index.js doctor # pre-flight check: tool resolution, connected probes, udev rules
node dist/index.js doctor --jsonRegistering with an MCP client
{
"mcpServers": {
"stm32-stlink": {
"command": "node",
"args": ["<path-to-this-repo>/stmcp/dist/index.js"]
}
}
}Configuration (environment variables)
Variable | Default | Purpose |
| — | Per-binary override (highest priority) |
| — | CubeCLT install root; subpaths resolved via |
| — | Default probe serial (omit to auto-select if exactly one is attached) |
|
| Default MCU device string |
|
|
|
|
| SWD/JTAG clock |
|
| Concurrent debug session cap |
|
| How long to wait for "Waiting for debugger connection..." |
|
|
|
| — | Optional log file (stderr always used regardless — stdout is reserved for MCP framing) |
|
| Enables the erase path |
|
| Enables |
|
| Allows |
| (unrestricted) | Comma-separated allowlist roots for ELF/bin file arguments |
|
| Max size for file arguments |
|
| Flash address window for the write guard (default: 128KB, STM32G431CB) |
Tools
Domain | Tool | Purpose |
Probe |
| List connected ST-LINK probes |
Session |
| Spawn gdbserver+gdb, load ELF symbols, connect |
Session |
| Clean session teardown |
Session |
| Session info (one, or all) |
Flash |
| One-shot flash via STM32_Programmer_CLI, no session needed |
Flash |
| Reflash via gdb |
Execution |
| Resume/continue |
Execution |
| Interrupt |
Execution |
| Reset (monitor reset [halt]) |
Execution |
| Step over/into/out |
Breakpoints |
| By file:line, symbol, or |
Memory |
| Raw memory access (write is guarded) |
Registers |
| Named core registers |
Registers |
| One-call Cortex-M SCB fault register dump (CFSR/HFSR/... decoded) |
Expressions |
| Symbol-aware evaluation via gdb MI |
Deferred to v2
SVD peripheral register tools (memory_read/write + evaluate_expression already reach everything by
address), live/streaming memory polling, a plugin system, per-chip memory-region allowlists,
arbitrary gdb monitor passthrough, and option-bytes/RDP tools (bricking-capable, intentionally
out of scope).
RTT
RTT (SEGGER Real Time Transfer — live, non-halting console/variable tracing) is intentionally
not implemented in this server. ST-LINK_gdbserver's GDB/MI stub has no non-stop mode, so
reading memory through this server's debug_connect session requires halting the core first —
which defeats RTT's purpose. The correct mechanism is direct AP memory access that never halts
the core (confirmed by reading ST's own STM32CubeMonitor source, which uses exactly this, and by
STM32_Programmer_CLI's -r32fast).
That's what strtt already does, and
strtt-mcp wraps it as its own MCP server
(strtt_start/strtt_stop/strtt_status/strtt_read/strtt_write). Register it alongside
this server rather than through it:
{
"mcpServers": {
"stm32-stlink": { "command": "node", "args": ["<...>/mcp-server/dist/index.js"] },
"strtt": {
"command": "node",
"args": ["<path-to-strtt-repo>/mcp/dist/index.js"],
"env": { "STRTT_BIN": "<path-to-strtt-binary>" }
}
}
}Start strtt_start with tcp: true to connect through the shared ST-LINK Server instead of
claiming the USB device directly — this lets it run concurrently with an open debug_connect
session here, since GdbServerProcess always passes -t/--shared to ST-LINK_gdbserver.
Without tcp: true, strtt and an open debug session will contend for the same probe.
Hardware verification runbook
With an ST-LINK and target attached:
node dist/index.js doctor # confirm probe + tools resolve
npx @modelcontextprotocol/inspector node dist/index.js # interactive tool testingThen, via the inspector or an MCP client:
list_probes→ the probe's serial appears.debug_connect { elfPath, device, interface: "swd", serial }→ returns asessionId.breakpoint_set { sessionId, location: "main" }→ returns a breakpoint number.debug_run { sessionId }→ halts withreason: "breakpoint-hit".register_read { sessionId, registers: ["pc","sp","lr","r0"] }.evaluate_expression { sessionId, expression: "<a known global>" }.read_fault_registers { sessionId }→ benign/zero flags right after reset.debug_disconnect { sessionId }→ confirm no orphaned processes:ps aux | grep -E 'ST-LINK_gdbserver|arm-none-eabi-gdb'.flash_standalone { file, reset: "hard", run: true }with no session open.Negative test: open a session, then call
flash_standaloneon the same serial → expectDEVICE_BUSY.
Note: debug_connect halts the target's CPU. Don't attach to a board that's actively driving
actuators/outputs in a way where an unplanned halt would be unsafe, without first confirming that's OK.
Available Tools
19 toolsbreakpoint_clearClear a breakpointA
Deletes a previously set breakpoint by its number.
Inputs: sessionId (required), breakpointNumber (required).
breakpoint_listList breakpointsA
Lists breakpoints currently tracked on a session (those set via breakpoint_set).
Inputs: sessionId (required).
breakpoint_setSet a breakpointB
Sets a breakpoint by file:line (e.g. main.c:42), symbol name (e.g. main), or address (e.g. *0x08000200).
Inputs: location (required), sessionId (required), condition, temporary.
debug_connectConnect a debug sessionA
Starts a debug session: spawns ST-LINK_gdbserver and arm-none-eabi-gdb (MI2), loads ELF symbols, and connects via target extended-remote.
Inputs: elfPath (required), apId, device, serial, +3 more.
debug_disconnectDisconnect a debug sessionA
Cleanly tears down a debug session's gdb and ST-LINK_gdbserver child processes.
Inputs: sessionId (required).
debug_haltHalt executionB
Interrupts the running target.
Inputs: sessionId (required).
debug_resetReset the targetA
Resets the target via ST-LINK_gdbserver's monitor reset command, optionally resuming afterward.
Inputs: sessionId (required), halt.
debug_runResume executionA
Resumes (continues) the target and waits for it to stop again (e.g. a breakpoint), up to a timeout.
Inputs: sessionId (required), waitForStopMs.
debug_session_statusDebug session statusA
Reports the status of one debug session (by id), or lists all active sessions if id is omitted.
Inputs: sessionId.
debug_stepSingle-stepB
Steps the target: 'over' (next line, step over calls), 'into' (step into calls), or 'out' (finish the current function).
Inputs: sessionId (required), mode, waitForStopMs.
evaluate_expressionEvaluate an expressionB
Symbol-aware expression evaluation in the current frame via gdb's -data-evaluate-expression — reads globals/locals by name, struct/array member access, pointer dereference, arithmetic, etc.
Inputs: sessionId (required), expression (required).
flash_load_in_sessionReflash firmware within a debug sessionA
Reflashes the currently loaded ELF via gdb's load (MI: -target-download) inside an already-open debug session. No USB conflict — ST-LINK_gdbserver retains ownership of the probe throughout.
Inputs: sessionId (required), runToMain, resetAfter.
flash_standaloneFlash firmware (standalone)A
One-shot flash via STM32_Programmer_CLI — no debug session required. Fails with DEVICE_BUSY if a debug session is already open on the same probe (it holds exclusive USB access); disconnect first, or use flash_load_in_session instead.
Inputs: file (required), run, reset, serial, +3 more.
list_probesList ST-LINK probesA
Lists connected ST-LINK probes via STM32_Programmer_CLI. Returns an empty list (not an error) if none are attached.
Inputs: no named parameters.
memory_readRead memoryA
Reads raw bytes from target memory at an address or symbol-address expression (e.g. '&my_global').
Inputs: length (required), address (required), sessionId (required).
memory_writeWrite memoryA
Writes raw bytes to target RAM/registers at an address. Blocked for addresses inside the flash window (use flash_standalone / flash_load_in_session for flash) unless STMCP_ALLOW_FLASH_ADDRESS_WRITE is set.
Inputs: address (required), bytesHex (required), sessionId (required).
read_fault_registersRead Cortex-M fault registersA
One-call dump of Cortex-M SCB fault registers (CFSR/HFSR/MMFAR/BFAR/SHCSR/CPUID/ICSR) plus PC/SP/LR, with CFSR/HFSR bits decoded to flag names. Raw evidence only — no root-cause interpretation.
Inputs: sessionId (required).
register_readRead core registersA
Reads named core registers (default: all general-purpose + sp/lr/pc/xpsr) via gdb MI.
Inputs: sessionId (required), registers.
register_writeWrite a core registerB
Writes a value to a named core register via gdb's -gdb-set $<register>=<value>.
Inputs: value (required), register (required), sessionId (required).
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 19 tools
Each tool targets a distinct action: session lifecycle, run control, breakpoints, register/memory access, and flashing are clearly separated. The only similar pair, flash_standalone and flash_load_in_session, is explicitly differentiated by requiring or not requiring an active debug session.
All tool names are lowercase snake_case and mostly follow a predictable domain-prefixed verb pattern such as breakpoint_set, memory_read, and debug_run. Minor exceptions like debug_session_status and flash_standalone break the strict verb_noun pattern but remain easy to anticipate.
19 tools is on the heavier side, but the embedded debug workflow legitimately spans session management, execution control, breakpoints, register/memory inspection, fault diagnosis, and flashing. Each tool has a justifiable role, so the count feels slightly over ideal rather than bloated.
The toolset covers the full core debug loop: connect/disconnect, run/halt/reset/step, breakpoint management, register and memory access, expression evaluation, fault register dumps, and both standalone and in-session flashing. Missing conveniences like stack backtraces or watchpoints are minor gaps, not workflow-breaking omissions.
Maintenance
Related MCP Connectors
MCP server for Klever blockchain smart contract development.
MCP server for progressive tool usage at any scale (see https://klavis.ai)
MCP server for Product Management
An MCP server that let you interact with Cycloid.io Internal Development Portal and Platform
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceA GDB/MI protocol server based on the MCP protocol, providing remote application debugging capabilities.68MIT
- AlicenseAqualityDmaintenanceStateful MCP server for driving debug probes (J-Link) to flash, debug, and inspect embedded targets. Enables AI agents to perform flash, memory, breakpoint, and ELF/SVD-aware operations conversationally.4149 PyPI10MIT
- AlicenseNot gradedqualityDmaintenanceMCP server for embedded debugging based on probe-rs, providing 22 tools for ARM Cortex-M and RISC-V microcontrollers, including connection, memory operations, breakpoints, flash programming, and RTT communication.2MIT
- AlicenseNot gradedqualityDmaintenanceAn MCP server that provides comprehensive debugging capabilities for J-Link debuggers, enabling memory, flash, register, and RTT operations through AI assistants.24 PyPI40MIT